diff options
author | comex <[email protected]> | 2020-11-25 17:18:26 -0500 |
---|---|---|
committer | Rodrigo Locatti <[email protected]> | 2020-11-25 20:02:04 -0300 |
commit | 13396c96ac5895240b846a1938655541e91b079a (patch) | |
tree | 223f01989fbc2c7d03ff657a7e62f167634cf4e9 /include | |
parent | 393fccea5bda5d1866aaa74f5e5c19a49445fa90 (diff) | |
download | sirit-13396c96ac5895240b846a1938655541e91b079a.tar.gz sirit-13396c96ac5895240b846a1938655541e91b079a.zip |
Use `requires` clauses to better disambiguate variadic and non-variadic overloads
Suppose you try to call, say, `AddEntryPoint` with a `std::vector<Id>`
as the `interfaces` argument - something that yuzu does. This can match
the non-variadic overload, since `std::vector<Id>` is implicitly
convertible to the argument type `std::span<const Id>`. But it can also
match the variadic overload, and the compiler sees that as a 'better'
match because it doesn't require implicit conversion. So it picks that
overload and promptly errors out trying to convert `std::vector<Id>` to
`Id`.
To make the compiler pick the right overload, you would have to
explicitly convert to `std::span<const Id>`, which is annoyingly
verbose.
To avoid this, add `requires` clauses to all variadic convenience
overloads, requiring each of the variadic arguments to be convertible to
the corresponding element type. If you pass a vector/array/etc., this
rules out the variadic overload as a candidate, and the call goes
through with the non-variadic overload.
Also, use slightly different code to forward to the non-variadic
overloads, that works even if the arguments need to be converted.
Note: I used this in a WIP branch updating yuzu to the latest version of
sirit.
Note 2: I tried to run clang-format on this, but it mangled the requires
clauses pretty horribly, so I didn't accept its changes. I googled it,
and apparently clang-format doesn't properly support concepts yet...
Diffstat (limited to 'include')
-rw-r--r-- | include/sirit/sirit.h | 77 |
1 files changed, 53 insertions, 24 deletions
diff --git a/include/sirit/sirit.h b/include/sirit/sirit.h index dd45d4f..7e1fd22 100644 --- a/include/sirit/sirit.h +++ b/include/sirit/sirit.h @@ -13,6 +13,7 @@ #include <span> #include <string> #include <string_view> +#include <type_traits> #include <unordered_set> #include <variant> #include <vector> @@ -61,11 +62,14 @@ public: std::span<const Id> interfaces = {}); /// Adds an entry point. + // TODO: Change std::is_convertible_v to std::convertible_to when compilers + // support it; same elsewhere. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) void AddEntryPoint(spv::ExecutionModel execution_model, Id entry_point, std::string_view name, Ts&&... interfaces) { AddEntryPoint(execution_model, std::move(entry_point), name, - std::span<const Id>{std::array{interfaces...}}); + std::span<const Id>({interfaces...})); } /// Declare an execution mode for an entry point. @@ -74,9 +78,9 @@ public: /// Declare an execution mode for an entry point. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Literal>) void AddExecutionMode(Id entry_point, spv::ExecutionMode mode, Ts&&... literals) { - const Literal stack_literals[] = {std::forward<Ts>(literals)...}; - AddExecutionMode(entry_point, mode, std::span<const Literal>{stack_literals}); + AddExecutionMode(entry_point, mode, std::span<const Literal>({literals...})); } /** @@ -144,8 +148,9 @@ public: /// Returns type struct. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id TypeStruct(Ts&&... members) { - return TypeStruct(std::span<const Id>{std::array{members...}}); + return TypeStruct(std::span<const Id>({members...})); } /// Returns type opaque. @@ -159,8 +164,9 @@ public: /// Returns type function. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id TypeFunction(Id return_type, Ts&&... arguments) { - return TypeFunction(return_type, std::span<const Id>{std::array{arguments...}}); + return TypeFunction(return_type, std::span<const Id>({arguments...})); } /// Returns type event. @@ -194,8 +200,9 @@ public: /// Returns a numeric scalar constant. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id ConstantComposite(Id result_type, Ts&&... constituents) { - return ConstantComposite(result_type, std::span<const Id>{std::array{constituents...}}); + return ConstantComposite(result_type, std::span<const Id>({constituents...})); } /// Returns a sampler constant. @@ -218,8 +225,9 @@ public: /// Call a function. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpFunctionCall(Id result_type, Id function, Ts&&... arguments) { - return OpFunctionCall(result_type, function, std::span<const Id>{std::array{arguments...}}); + return OpFunctionCall(result_type, function, std::span<const Id>({arguments...})); } // Flow @@ -230,10 +238,11 @@ public: /// Declare a structured loop. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpLoopMerge(Id merge_block, Id continue_target, spv::LoopControlMask loop_control, Ts&&... literals) { return OpLoopMerge(merge_block, continue_target, loop_control, - std::span<const Id>{std::array{literals...}}); + std::span<const Id>({literals...})); } /// Declare a structured selection. @@ -301,8 +310,9 @@ public: /// Create a pointer into a composite object that can be used with OpLoad and OpStore. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpAccessChain(Id result_type, Id base, Ts&&... indexes) { - return OpAccessChain(result_type, base, std::span<const Id>{std::array{indexes...}}); + return OpAccessChain(result_type, base, std::span<const Id>({indexes...})); } /// Extract a single, dynamically selected, component of a vector. @@ -317,6 +327,7 @@ public: /// Make a copy of a composite object, while modifying one part of it. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Literal>) Id OpCompositeInsert(Id result_type, Id object, Id composite, Ts&&... indexes) { const Literal stack_indexes[] = {std::forward<Ts>(indexes)...}; return OpCompositeInsert(result_type, object, composite, @@ -328,6 +339,7 @@ public: /// Extract a part of a composite object. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Literal>) Id OpCompositeExtract(Id result_type, Id composite, Ts&&... indexes) { const Literal stack_indexes[] = {std::forward<Ts>(indexes)...}; return OpCompositeExtract(result_type, composite, std::span<const Literal>{stack_indexes}); @@ -338,8 +350,9 @@ public: /// Construct a new composite object from a set of constituent objects that will fully form it. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpCompositeConstruct(Id result_type, Ts&&... ids) { - return OpCompositeConstruct(result_type, std::span<const Id>{std::array{ids...}}); + return OpCompositeConstruct(result_type, std::span<const Id>({ids...})); } // Annotation @@ -349,6 +362,7 @@ public: /// Add a decoration to target. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Literal>) Id Decorate(Id target, spv::Decoration decoration, Ts&&... literals) { const Literal stack_literals[] = {std::forward<Ts>(literals)...}; return Decorate(target, decoration, std::span<const Literal>{stack_literals}); @@ -358,6 +372,7 @@ public: std::span<const Literal> literals = {}); template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Literal>) Id MemberDecorate(Id structure_type, Literal member, spv::Decoration decoration, Ts&&... literals) { const Literal stack_literals[] = {std::forward<Ts>(literals)...}; @@ -621,9 +636,10 @@ public: /// Execute an instruction in an imported set of extended instructions. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpExtInst(Id result_type, Id set, std::uint32_t instruction, Ts&&... operands) { return OpExtInst(result_type, set, instruction, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Result is x if x >= 0; otherwise result is -x. @@ -777,10 +793,11 @@ public: /// Sample an image with an implicit level of detail. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageSampleImplicitLod(Id result_type, Id sampled_image, Id coordinate, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageSampleImplicitLod(result_type, sampled_image, coordinate, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Sample an image using an explicit level of detail. @@ -790,10 +807,11 @@ public: /// Sample an image using an explicit level of detail. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageSampleExplicitLod(Id result_type, Id sampled_image, Id coordinate, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageSampleExplicitLod(result_type, sampled_image, coordinate, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Sample an image doing depth-comparison with an implicit level of detail. @@ -803,11 +821,12 @@ public: /// Sample an image doing depth-comparison with an implicit level of detail. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageSampleDrefImplicitLod(Id result_type, Id sampled_image, Id coordinate, Id dref, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageSampleDrefImplicitLod(result_type, sampled_image, coordinate, dref, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Sample an image doing depth-comparison using an explicit level of detail. @@ -817,11 +836,12 @@ public: /// Sample an image doing depth-comparison using an explicit level of detail. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageSampleDrefExplicitLod(Id result_type, Id sampled_image, Id coordinate, Id dref, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageSampleDrefExplicitLod(result_type, sampled_image, coordinate, dref, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Sample an image with with a project coordinate and an implicit level of detail. @@ -831,10 +851,11 @@ public: /// Sample an image with with a project coordinate and an implicit level of detail. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageSampleProjImplicitLod(Id result_type, Id sampled_image, Id coordinate, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageSampleProjImplicitLod(result_type, sampled_image, coordinate, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Sample an image with a project coordinate using an explicit level of detail. @@ -844,10 +865,11 @@ public: /// Sample an image with a project coordinate using an explicit level of detail. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageSampleProjExplicitLod(Id result_type, Id sampled_image, Id coordinate, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageSampleProjExplicitLod(result_type, sampled_image, coordinate, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Sample an image with a project coordinate, doing depth-comparison, with an implicit level of @@ -859,11 +881,12 @@ public: /// Sample an image with a project coordinate, doing depth-comparison, with an implicit level of /// detail. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageSampleProjDrefImplicitLod(Id result_type, Id sampled_image, Id coordinate, Id dref, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageSampleProjDrefImplicitLod(result_type, sampled_image, coordinate, dref, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Sample an image with a project coordinate, doing depth-comparison, using an explicit level @@ -875,11 +898,12 @@ public: /// Sample an image with a project coordinate, doing depth-comparison, using an explicit level /// of detail. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageSampleProjDrefExplicitLod(Id result_type, Id sampled_image, Id coordinate, Id dref, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageSampleProjDrefExplicitLod(result_type, sampled_image, coordinate, dref, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Fetch a single texel from an image whose Sampled operand is 1. @@ -889,10 +913,11 @@ public: /// Fetch a single texel from an image whose Sampled operand is 1. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageFetch(Id result_type, Id sampled_image, Id coordinate, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageFetch(result_type, sampled_image, coordinate, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Gathers the requested component from four texels. @@ -902,10 +927,11 @@ public: /// Gathers the requested component from four texels. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageGather(Id result_type, Id sampled_image, Id coordinate, Id component, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageGather(result_type, sampled_image, coordinate, component, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Gathers the requested depth-comparison from four texels. @@ -915,10 +941,11 @@ public: /// Gathers the requested depth-comparison from four texels. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageDrefGather(Id result_type, Id sampled_image, Id coordinate, Id dref, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageDrefGather(result_type, sampled_image, coordinate, dref, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Read a texel from an image without a sampler. @@ -928,10 +955,11 @@ public: /// Read a texel from an image without a sampler. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageRead(Id result_type, Id sampled_image, Id coordinate, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageRead(result_type, sampled_image, coordinate, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Write a texel to an image without a sampler. @@ -941,10 +969,11 @@ public: /// Write a texel to an image without a sampler. template <typename... Ts> + requires (... && std::is_convertible_v<Ts, Id>) Id OpImageWrite(Id image, Id coordinate, Id texel, spv::ImageOperandsMask image_operands, Ts&&... operands) { return OpImageWrite(image, coordinate, texel, image_operands, - std::span<const Id>{std::array{operands...}}); + std::span<const Id>({operands...})); } /// Extract the image from a sampled image. |