Enable_if Add a function parameter that has a default argument?

I can not understand the second scenario presented here . It says:

• Scenario 2: adding a function parameter that has a default argument:

template <your_stuff> your_return_type_if_present yourfunction(args, enable_if_t<your condition, FOO> = BAR) { // ... } 

Scenario 2 leaves the parameter unnamed. You could say ::type Dummy = BAR , but the name Dummy does not matter, and giving it a name is likely to trigger a warning about an invalid parameter. You must select the parameter type of the FOO function and the BAR argument is the default. You could say int and 0 , but then users of your code could accidentally pass an extra integer to the function, which would be ignored. Instead, we recommend using void ** and 0 or nullptr , because almost nothing is converted to void ** :

 template <your_stuff> your_return_type_if_present yourfunction(args, typename enable_if<your_condition, void **>::type=nullptr) { // ... } 

If scenario 2 leaves the parameter unnamed, then what can it be used for? Is there a way to make code like this work using enable_if ?

 enum otype {oadd,omull}; template<otype o> int add(int num1, std::enable_if<o == oadd, int>::type int= num2) { if (o == omull) return num1 * num1; if (o == oadd ) return num1 + num2; } 
+5
source share
2 answers

enable_if examples (if this helps):

For functions with a non-void return type:

Under one condition:

 template <template T, typename std::enable_if<!std::is_same<T,std::string>::value>::type* = nullptr > T func(T x){} 

For several conditions:

 template <template T, typename std::enable_if<!std::is_same<T,std::string>::value &&!std::is_same<T,int>::value>::type* = nullptr > T func(T x){} 


For functions with return type void:

Under one condition:

 template <template T> typename std::enable_if<!std::is_same<T,std::string>::value>::type func(T x){} 

For several conditions:

 template <template T> typename std::enable_if<!std::is_same<T,std::string>::value &&!std::is_same<T,int>::value>::type func(T x){} 

Remember to include #include <type_traits>

+3
source

Microsoft's documentation there is as clear as dirt. Use instead.

Providing a function template with an undefined form default parameter:

 typename enable_if<your_condition, void **>::type = nullptr 

(as the MS scribe suggests), it is useful in the case - and only in the case - you want to write several overloads of the function template with different behaviors that are controlled by one or more template arguments. Then by replacing your_condition condition expressing the corresponding requirement for the template argument (s), you can enroll SFINAE . to select the specific overload that you want to create for the given template arguments.

The SFINAE parameter — let this cause that — is an unused instantiated function; it exists solely to provoke SFINAE in the function overload resolution pattern. Therefore, it can be nameless, and therefore, it must be defaulted: this should not force you to provide an additional, useless argument when you call the function template.

For instance:

 #include <type_traits> #include <iostream> template <typename T> T foo(T && t, typename std::enable_if<std::is_same<T,int>::value, void **>::type = nullptr) { std::cout << "Doubling " << t << " gives " << (t + t) << std::endl; return t + t; } template <typename T> T foo(T && t, typename std::enable_if<!std::is_same<T,int>::value, void **>::type = nullptr) { std::cout << "Squaring " << t << " gives " << (t * t) << std::endl; return t * t; } using namespace std; int main() { cout << foo(2) << endl; cout << foo(3.3) << endl; return 0; } 

Exit:

 Doubling 2 gives 4 4 Squaring 3.3 gives 10.89 10.89 

In these two overloads of the foo function template, the first doubles enter the argument T , and the second doubles the square of its argument, and the SFINAE parameter is used to determine whether the doubling overload will repeat if T is int and that squaring will be chosen differently.

When T is int , the condition is:

 !std::is_same<T,int>::value 

which controls the SFINAE squaring overload parameter is false. as a result, a type specifier:

 typename std::enable_if<!std::is_same<T,int>::value, void **>::type = nullptr 

unable to compile. This is a replacement failure in pattern resolution. Substituting int for T in quadratic overload is not viable. Thus, it is excluded from work, and there is only a doubling reset to create an instance of a function call.

When T (say) is double , not int , the exact opposite happens and only the quadratic overload can withstand the resolution of the template. Call foo(2) and you get a double. Call foo(3.3) and you will get a square.

The MS MS of SFINAE is useless here.

 template< bool B, class T = void > struct enable_if; 

according to C ++ 11 Standard and later, the default is T - void . So for example:

 typename std::enable_if<some_condition, void **>::type = nullptr 

can also be shortened to:

 typename std::enable_if<some_condition>::type * = nullptr 

And with C ++ 14, the standard has:

 template< bool B, class T = void > using enable_if_t = typename enable_if<B,T>::type 

Thus, the same SFINAE parameter can be further reduced to:

 std::enable_if_t<some_condition> * = nullptr 

To apply the SFINAE function template parameter to the case that you indicated in your message, you should write:

 enum ops { add, multiply }; template<ops Op> int op(int const & lhs, int const & rhs, std::enable_if_t<Op == add> * = nullptr) { return lhs + rhs; } template<ops Op> int op(int const & lhs, int const & rhs, std::enable_if_t<Op == multiply> * = nullptr) { return lhs * rhs; } ... auto i = op<add>(2,3); auto j = op<multiply>(2,3); ... // C++14 
+6
source

Source: https://habr.com/ru/post/1215316/


All Articles