Default Specialization with Multiple Conditions

I would like to define functions for integer types, strings, and other types.

I can write:

template<typename T, typename = std::enable_if<std::is_integral<T>::value>::type>
void foo();

template<typename T, typename = std::enable_if<std::is_same<std::string>::value>::type>
void foo();

But how can I define a function that will be called in other cases (if Tit is not an integral type, but not std::string)?

+4
source share
3 answers

@ Jarod42 was right. I chose the wrong way to use SFINAE. In fact, I had to use std :: enable_if in the return type declaration. And in order to define the function "by default" (for all other types), I just need to define a function with the same name and ...as input parameters.

template<typename T>
std::enable_if_t<std::is_integral<T>::value>
foo() { std::cout << "integral"; }

template<typename T>
std::enable_if_t<std::is_same<T, std::string>::value>
foo() { std::cout << "string"; }

template<typename T>
void foo(...) { std::cout << "other"; }
0

. . SFINAE . .

. :

template<typename T, std::enable_if_t<std::is_integral<T>::value>* = nullptr>
void foo() { std::cout << "Integral\n"; }

template<typename T, std::enable_if_t<std::is_same<T, std::string>::value>* = nullptr>
void foo() { std::cout << "Str\n"; }

template<typename T, std::enable_if_t<!std::is_integral<T>::value && !std::is_same<T, std::string>::value>* = nullptr>
void foo() { std::cout << "Something else\n"; }

int main(void)
{
    foo<int>();
    foo<std::string>();
    foo<float>();
    return 0;
}

:

Integral
Str
Something else

, , . SFINAE :

template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type foo(const T&) { std::cout << "Integral\n"; }

template<typename T>
typename std::enable_if<std::is_same<T, std::string>::value>::type foo(const T&) { std::cout << "Str\n"; }

template<typename T>
typename std::enable_if<!std::is_integral<T>::value && !std::is_same<T, std::string>::value>::type
foo(const T&) { std::cout << "Something else\n"; }

:

foo(1);
foo(std::string("fdsf"));
foo(1.1f);

, std::string :

template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type foo(const T&) { std::cout << "Integral\n"; }

template<typename T>
typename std::enable_if<!std::is_integral<T>::value && !std::is_same<T, std::string>::value>::type
foo(const T&) { std::cout << "Something else\n"; }

void foo(const std::string&) { std::cout << "Str\n"; }
+2

, - , n sfinae'd foo:

std::enable_if<!std::is_integral<T>::value && !std::is_same<T, std::string>::value>::type

, ( ).
:

#include <iostream>
#include <utility>
#include <string>

template<int N> struct Choice: Choice<N-1> {};
template<> struct Choice<0> {};

template<typename T, typename... Args>
std::enable_if_t<std::is_integral<T>::value>
bar(Choice<2>, Args&&...) { std::cout << "integral" << std::endl; }

template<typename T, typename... Args>
std::enable_if_t<std::is_same<T, std::string>::value>
bar(Choice<1>, Args&&...) { std::cout << "string" << std::endl; }

template<typename T, typename... Args>
void bar(Choice<0>, Args&&...) { std::cout << "whatever" << std::endl; }

template<typename T, typename... Args>
void foo(Args&&... args) { bar<T>(Choice<100>{}, std::forward<Args>(args)...); }

int main() {
    foo<bool>("foo");
    foo<std::string>(42);
    foo<void>(.0, "bar");
}

, , .

, N 0. , , T sfinae.
sfinae i- , Choice<0> ( , std::enable_if<!std::is_integral<T>::value && !std::is_same<T, std::string>::value>::type).
( ) , , , Choice<N>.

Coliru.

+2

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


All Articles