Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use a enable_if that does not depend on method's template parameter

Tags:

People also ask

Can we use non-type parameters as arguments template?

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 allowed for non-type template?

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.

Which is a correct example of template parameters?

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.

CAN default arguments be used with the template?

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…?)