Non-type template arguments are normally used to initialize a class or to specify the sizes of class members. For non-type integral arguments, the instance argument matches the corresponding template parameter as long as the instance argument has a value and sign appropriate to the parameter type.
Which parameter is legal for non-type template? Explanation: The following are legal for non-type template parameters:integral or enumeration type, Pointer to object or pointer to function, Reference to object or reference to function, Pointer to member.
For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.
You cannot give default arguments to the same template parameters in different declarations in the same scope. The compiler will not allow the following example: template<class T = char> class X; template<class T = char> class X { };
I'm trying to use std::enable_if
and SFINAE to switch out the implementation of a class template's method based purely on the template parameters of the class. Example:
#include <type_traits>
template<class T1, class T2>
class Foo {
template<class InnerT, class ... Args>
typename std::enable_if<std::is_same<T1, T2>::value, void>::type
bar(InnerT param) {};
template<class InnerT, class ... Args>
typename std::enable_if<!std::is_same<T1, T2>::value, void>::type
bar(InnerT param) {};
};
int main() {
Foo<int, int> f;
}
Here, bar()
should behave differently based on whether T1
and T2
are the same type or not. However, this code does not compile. Neither GCC nor clang tell me anything useful. I suspect the problem is that the std::enable_if
condition does not depend on the parameters of bar()
, i.e., not on its immediate context as specified in paragraph 17.8.2, point 8, of the standard.
This assumption is supported by the fact that this code compiles fine:
#include <type_traits>
class DummyClass {};
template<class T1, class T2>
class Foo {
template<class InnerT, class ... Args>
typename std::enable_if<std::is_same<T1, T2>::value ||
std::is_same<InnerT, DummyClass>::value, void>::type
bar(InnerT param) {};
template<class InnerT, class ... Args>
typename std::enable_if<!std::is_same<T1, T2>::value ||
std::is_same<InnerT, DummyClass>::value, void>::type
bar(InnerT param) {};
};
int main() {
Foo<int, int> f;
}
Now the expression inside the std::enable_if
depends on the "immediate context", namely InnerT
, even though that part of the expression always evaluates to false
.
It looks like I can use this as a workaround, but that feels really hacky and ugly. How do you solve this problem "correctly"? A thought I had was to add an additional template parameter (call it DummyType
) to bar()
, which defaults to e.g. DummyType = T1
, and then check std::is_same<DummyType, T2>
, but the fact that bar()
takes a parameter pack makes this impossible (or does it…?)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With