Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Member function template selection and SFINAE

I've been trying to understand the way C++ selects templates. Namely, consider the following code sample:

template <typename R>
class Curious
{
public:
    template <typename T, typename std::enable_if<std::is_const<T>::value, int>::type = 33>
    void test1() {}

    template <typename T, typename std::enable_if<!std::is_const<T>::value, int>::type = 33>
    void test1() {}

    template <typename T, typename = typename std::enable_if<std::is_const<T>::value>::type>
    void test2() {}

    template <typename T, typename = typename std::enable_if<!std::is_const<T>::value>::type>
    void test2() {}

    template <typename std::enable_if<std::is_const<R>::value>::type * = nullptr>
    void test3() {}

    template <typename std::enable_if<!std::is_const<R>::value>::type * = nullptr>
    void test3() {}

    // works
    template <typename T = void>
    typename std::enable_if<std::is_const<R>::value, T>::type test4() {}

    template <typename T = void>
    typename std::enable_if<!std::is_const<R>::value, T>::type test4() {}

    // also works
    template <typename T = void, typename std::enable_if<std::is_const<R>::value, T>::type * = nullptr>
    void test5() {}

    template <typename T = void, typename std::enable_if<!std::is_const<R>::value, T>::type * = nullptr>
    void test5() {}
}; // Curious

The first two functions (test1) work fine (why?):

Curious<int> curious;
curious.test1<int>();
curious.test1<const int>();

While the rest of them cause compilation errors. Regarding the function test2 the compiler claims I'm trying to create a duplicate:

error C2535: 'void Curious::test2(void)': member function already defined or declared

Here the documentation says:

A common mistake is to declare two function templates that differ only in their default template arguments. This is illegal because default template arguments are not part of function template's signature, and declaring two different function templates with the same signature is illegal.

So it seems to be the case. However, I don't see that much difference from the first two functions, which also have the default template argument. Thus we have a default type (test2 - doesn't work) against a default value (test1 - works). Is there any rule about it?

In case of test3:

error C2039: 'type': is not a member of 'std::enable_if'
Like in the first case this time the member function template has a default non-type parameter, but it depends on the class template parameter. Now SFINAE doesn't skip the wrong one (also not sure why).

In the fourth case SFINAE resolves the template by the return type. But don't these test4 functions have identical signature? As they differ only in the return type.

As far as I understand, in the fifth case adding extra parameter makes test5 signature dependent on the function template parameter, therefore SFINAE kicks in and resolution works.

I'm quite confused about how C++ deals with these templates. Could somebody be so kind to clear these things up?

like image 968
mentalmushroom Avatar asked Sep 15 '16 12:09

mentalmushroom


People also ask

What is member function template?

The term member template refers to both member function templates and nested class templates. Member function templates are function templates that are members of a class or class template.

What is Sfinae used for?

Substitution failure is not an error (SFINAE) refers to a situation in C++ where an invalid substitution of template parameters is not in itself an error. David Vandevoorde first introduced the acronym SFINAE to describe related programming techniques.

How would you define member function of template class?

Member functions of class templates (C++ only)You may define a template member function outside of its class template definition. The overloaded addition operator has been defined outside of class X . The statement a + 'z' is equivalent to a. operator+('z') .

What are templates explain functions template with suitable example?

Function Templates We write a generic function that can be used for different data types. Examples of function templates are sort(), max(), min(), printArray(). Know more about Generics in C++. CPP.


1 Answers

  • With default value removed, for test1, you have:

    template <typename T, typename std::enable_if<std::is_const<T>::value, int>::type>
    void test1();
    
    template <typename T, typename std::enable_if<!std::is_const<T>::value, int>::type>
    void test1();
    

    Which have clearly different signatures.

  • For test2:

    template <typename T, typename> void test2();
    
    template <typename T, typename> void test2();
    

    Which are clearly identical signatures.

  • For test3, SFINAE doesn't apply as you have hard error as R is fixed in the class and your enable_if doesn't depend of template parameter of the function.

  • For test4, there is an exception about signature for template function as overload may differ only by return type so

    int foo();
    char foo(); // Illegal.
    

    but

    template <typename T> int foo();
    template <typename T> char foo(); // legal, even it is not trivial to call
    

    In addition, std::enable_if<!std::is_const<R>::value, T>::type depends on template parameter T so it is ok.

  • For test5, second template parameter depends on first template parameter T, so it is ok too.

like image 111
Jarod42 Avatar answered Sep 18 '22 14:09

Jarod42