【问题标题】:Specialize function template for set of types [duplicate]为一组类型专门化功能模板[重复]
【发布时间】:2018-08-21 21:28:42
【问题描述】:

是否可以为不同的集合类型创建具有不同行为的函数模板?

假设一个带有模板参数的函数,它应该接受 ANY 类型,并且没有编译失败

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

当然,这不会为没有operator&lt;&lt; 的类型编译。我只想在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 来专门化函数模板?

附:升压无关紧要 附言我已经看到了这个答案Specialize Many Templates for a Set of Types,但我不知道如何采用它,即所有可能的类型都可以传递给函数,而不仅仅是几个预定义的

【问题讨论】:

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


    【解决方案1】:

    您可以直接对 SFINAE 使用所需的表达式std::cout &lt;&lt; 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的价值范畴的。

    【讨论】:

      【解决方案2】:

      试试这个:

      #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
      

      有什么区别?

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

      【讨论】:

        【解决方案3】:

        您是否尝试过使用带有返回类型的 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>{}); }
        

        (注意:代码未经测试)

        【讨论】:

        • 第一个编译好,但需要“返回 arg;”
        • @AlexLarionov - 抱歉:“需要'返回 arg;'”是什么意思?您是否需要一个返回值的函数 (arg?),而不是 void 函数?无论如何:第二个修改(在std::is_arithmetic 末尾忘记了{};对不起)
        • 我的意思是,第一个清单定义了返回 typename std::enable_if&lt;std::is_arithmetic&lt;T&gt;::value&gt;::type 类型值的函数模​​板,编译器声称它们在两个函数中都返回。如果有可能将函数变成返回无效,我会喜欢它
        • @AlexLarionov - 当std::is_arithmetic&lt;T&gt;::valuetrue 时,typename std::enable_if&lt;std::is_arithmetic&lt;T&gt;::value&gt;::typevoidstd::enable_if&lt;std::is_arithmetic&lt;T&gt;::value&gt; 的默认类型);否则什么都没有(所以替换失败)。如果您想要不同的类型(例如:int),您必须明确作为第二个参数:typename std::enable_if&lt;std::is_arithmetic&lt;T&gt;::value, int&gt;::type
        • ty,没有注意到缺少第二个参数
        猜你喜欢
        • 2017-01-17
        • 2014-05-13
        • 2011-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多