为一组类型专门化功能模板

时间:2018-08-21 21:28:43

标签: c++ c++11 templates sfinae

是否可以为不同类型的创建具有不同行为的功能模板?

假设具有模板参数的函数应接受 ANY 类型,而不会编译失败

template<typename T>
void foo(T arg){
    std::cout << arg;
} 

当然,对于没有operator<<的类型,它不会编译。我只想用std::cout来写朴素的类型(即数值型,std:stringconst char *),对于其他类型则没有任何内容可打印。 因此,我尝试了此操作(为简化起见,我省略了对std:stringconst char *的检查)

template<typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
void foo(T arg){
    std::cout << arg;
}

template<typename T, typename = typename std::enable_if<!std::is_arithmetic<T>::value, T>::type>
void foo(T arg){

}

也就是说,必须生成没有潜在歧义的重载函数。当然,代码不会编译,因为模板的参数不是模板签名的一部分(因此,有两个模板具有相同的签名)。那么有什么玩法吗?

我看到了使后者充当主模板以及针对声明的类型来创建模板专业化的解决方案,但我不想用相同的定义来夸大我的代码(可能会打印更多类型)。有什么方法可以使用std::enable_if或smth来专门化功能模板?

P.S。提升无关紧要 P.P.S.我已经看到了这个答案Specialize Many Templates for a Set of Types,但是我不知道如何采用它,那就是所有可能的类型都可以传递给函数,而不仅仅是少数预定义的

3 个答案:

答案 0 :(得分:3)

您可以直接为SFINAE使用所需的表达式std::cout << arg。示例:

template<typename T>
auto foo_imp(T&& arg, int) -> decltype(std::cout << std::forward<T>(arg), throw) /* -> is void */ {
    std::cout << std::forward<T>(arg);
}

template<typename T>
void foo_imp(T&&, long) {
    // Do nothing.
}

template<typename T>
void foo(T&& arg)  {
    foo_imp(std::forward<T>(arg), 0); // int is the best match for 0.
}

struct X {};

int main() {
    foo(1);   // calls foo_imp(int&&, int)
    foo(X{}); // calls foo_imp(X&&, long)
}

在上面的std::forward中,用于完善地保存arg的值类别。

答案 1 :(得分:0)

您是否曾使用std::enable_if和返回类型来尝试SFINAE?

template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value>::type foo(T arg)
 { std::cout << arg; }

template<typename T>
typename std::enable_if<!std::is_arithmetic<T>::value>::type foo(T arg)
 { }

还是标签派发?

template <typename T>
void foo_helper (T arg, std::true_type const &)
 { std::cout << arg; }

template <typename T>
void foo_helper (T arg, std::false_type const &)
 { }

template <typename T>
void foo (T arg)
 { foo_helper(arg, std::is_arithmetic<T>{}); }

(警告:代码未经测试)

答案 2 :(得分:0)

尝试一下:

#include <iostream>

template<typename T, typename std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
void foo(T arg){
    std::cout << arg << '\n';
}

template<typename T, typename std::enable_if_t<!std::is_arithmetic<T>::value, int> = 0>
void foo(T arg){
    std::cout << "not an arithmetic type\n";
}

int main() {
    foo(4.6);
    foo("bla");
}

这需要C ++ 14(对于C ++ 11使用std::enable_if)并输出:

4.6
not an arithmetic type

有什么区别?

如果满足条件,我们将在这里创建一个int,其默认值为0作为第二个模板参数。