AAA
AAA

Reputation: 448

How to call templated type with

I am trying to create a template function that has two different implementations based on a template argument. While the first one is specific for I/O manipulators and the second one is for any general case.

template <typename T>
typename std::enable_if<
            std::is_same<decltype(std::setw), T>::value>::type
foo(T& t){
        cout << "enabled" << std::endl;
}

template <typename T>
void foo(T& t){
        cout << "Normal" << std::endl;
}

template <typename... Ts>
void foohelper(Ts... t){
        foo(t...);
}
int main(){
        foohelper(std::setprecision(3)); // It should print enabled, but printing Normal
}

Currently it is not doing what I am trying to implement. How can I fix it?

Upvotes: 3

Views: 270

Answers (3)

Tony Delroy
Tony Delroy

Reputation: 106244

You don't need to use enable_if - just specialise the template below the main definition of template foo.

template <>
void foo<decltype(std::setw(0))>(decltype(std::setw(0))& t)
{
        cout << "enabled" << std::endl;
}

Upvotes: 5

Guillaume Racicot
Guillaume Racicot

Reputation: 41840

You can use SFINAE by comparing the return type of the function std::setprecision. Since the return type is unspecified, you will need decltype and std::declval.

Here's the solution:

template <typename T, typename std::enable_if<std::is_same<decltype(std::setprecision(std::declval<int>())), typename std::decay<T>::type>::value, int>::type = 0>
void foo(T&& t) {
    cout << "enabled" << std::endl;
}

Here I changed T& to T&& so it accept any kind of reference. That remove the use of your foohelper.

Furthermore, is the type comparison, I decay the type T, since the comparison won't work if one of the type is a reference type, because T& is not the same as T. The use of std::decay will effectively remove the reference.

Notice that I moved the SFINAE construct inside the template declaration. This is to keep SFINAE away from the return type. The use of non type template parameter defaulted to 0 won't affect the use of the function and will ensure that no one can effectively bypass the SFINAE check.

Edit:

You can replace std::declval<int>() with 0 in your case. I was just willing to show how you can use this tool to replace actual value. There are a lot of cases where you can't have values.

Upvotes: 2

user6323422
user6323422

Reputation: 135

The return type of these functions are unspecified. That means you can't use type_traits to compare them. As an example, here's libcxx:

// Definitions omitted
T2 setiosflags (ios_base::fmtflags mask);
T3 setbase(int base);
template<charT> T4 setfill(charT c);
T5 setprecision(int n);
T6 setw(int n);

T5, T6, etc. refer to __imo_t4 etc., an internal structure that does the actual work of the manipulator. Since they all have different return types, the functions have different types. Hence they'll all be different.

Upvotes: 2

Related Questions