Reputation: 129
I'm trying to declare a template function that...
Is this possible?
The code below compiles, however both versions require 3 parameters. I need it to only need 2 parameters when the template boolean is false and the resulting usage of the function - the user only needs to supply 2 parameters.
Ideally this is a single function, so code duplication can be avoided as the function definition is very simple.
Static: Iterate thru area, apply hash to nodes.
Dynamic: Iterate thru area, transform node by 2D rotation, apply hash to node.
Ideally the selection of the logic to use can be evaluated at compile time aswell
if constexpr(Dynamic) ...
template<bool const Dynamic>
void setHashAt(rect2D_t area, uint32_t const hash, std::conditional_t<Dynamic, v2_rotation_t const&, void> vR)
Thanks!
Upvotes: 0
Views: 619
Reputation: 217398
Simple overload seems simpler, but to directly answer your question, you might (ab)use of variadic template and SFINAE:
template<bool Dynamic,
typename ... Ts,
std::enable_if_t<(Dynamic == false && sizeof...(Ts) == 0)
|| (Dynamic == true && sizeof...(Ts) == 1
&& std::is_convertible_v<std::tuple_element_t<0, std::tuple<Ts...>>,
v2_rotation_t>)
, bool> = false>
void setHashAt(rect2D_t area, uint32_t const hash, const Ts&... vR);
With the caveat that 3rd argument should be deducible (so no {..}
).
Upvotes: 2
Reputation: 2812
This is a small variation to your solution
#include <type_traits>
struct None{};
template<bool select>
void foo(int, std::conditional_t<select, int, None> = None{}) {
}
int main() {
foo<false>(1);
foo<true>(1,2);
// foo<false>(1,2); // fails
// foo<true>(1); // fails
}
I don't think this is a clean solution, but instead overloading and refactoring the code to avoid duplication should be the right approach (as suggested in comments).
Upvotes: 1
Reputation: 402
Sure, you can do that through SFINAE;
#include <type_traits>
template <const bool EnableThird, std::enable_if_t<EnableThird, int> = 0>
void dynamic_parameter_count(int one, int two, int three) {
std::cout << "EnableThird was true\n";
}
template <const bool EnableThird, std::enable_if_t<!EnableThird, int> = 0>
void dynamic_parameter_count(int one, int two) {
std::cout << "EnableThird was false\n";
}
And you can then simply invoke using;
dynamic_parameter_count<true>(1, 2, 3);
dynamic_parameter_count<false>(1, 2);
This works by enabling or disabling one of the template instantiations based on the template parameters. You do, in fact, need two templates for this as far as I know. I'm not sure if you can do this in one template.
You can also simply specify two versions for the same function, however;
void parameter_count(int one, int two, int three) {
std::cout << "3 Parameters\n";
}
void parameter_count(int one, int two) {
std::cout << "2 Parameters\n";
}
To me, without knowing the context you are working in, this seems more logical.
Or even:
#include <optional>
void parameter_count(int one, int two, std::optional<int> three = {}) {
if (three.has_value()) {
std::cout << "3 Parameters\n";
} else {
std::cout << "2 Parameters\n";
}
}
Upvotes: 3