【问题标题】:Is There a Way to Declare a typename for a Templatized Function?有没有办法为模板化函数声明类型名?
【发布时间】:2015-02-23 18:22:10
【问题描述】:

所以,我有this templatized function(我知道这很难看。)

虽然我的意图不是默认模板参数,但我的意图是创建一个派生自 Ttypename,它可以在用户无法分配的 caster 中使用。

我的问题是如何为用户无法作为参数传递的模板化函数创建typename

举个例子:

template <typename T>
typename R = std::conditional<sizeof(T) == 4, char, short>;
R foo(T bar){return R(bar);}

显然,这段代码无法编译,但这是我想要完成的行为。函子是做到这一点的唯一方法吗?

【问题讨论】:

    标签: c++ templates parameters typename function-templates


    【解决方案1】:

    在 C++14 中,这可以通过返回类型推导优雅地解决。

    // C++14
    #include <type_traits>
    
    template <typename T>
    decltype(auto)
    foo(T bar)
    {
      using R = std::conditional_t<sizeof(T) == 4, char, short>;
      return static_cast<R>(bar);
    }
    

    在 C++11 中,您必须重复类型计算。

    // C++11
    #include <type_traits>
    
    template <typename T>
    typename std::conditional<sizeof(T) == 4, char, short>::type
    foo(T bar)
    {
      using R = typename std::conditional<sizeof(T) == 4, char, short>::type;
      return static_cast<R>(bar);
    }
    

    这可以通过使用decltype 来确定类型来缩短一点。

    // C++11
    #include <type_traits>
    
    template <typename T>
    typename std::conditional<sizeof(T) == 4, char, short>::type
    foo(T bar)
    {
      using R = decltype(foo(bar));
      return static_cast<R>(bar);
    }
    

    但坦率地说,使用简单的默认类型参数有什么问题?

    // C++11
    #include <type_traits>
    
    template <typename T,
              typename R = typename std::conditional<sizeof(T) == 4, char, short>::type>
    R
    foo(T bar)
    {
      return static_cast<R>(bar);
    }
    

    请注意,我已将return 语句中R 的值初始化替换为static_cast,以使编译器关于缩小转换的警告静音。不过,您确定这是您想要的吗?

    【讨论】:

    • @JonathanMee 从 C++11 开始,您可以使用 template&lt;typename T, typename U&gt; auto foo(T t, U u) -&gt; decltype(t + u) { return t + u; }。这是一个尾随返回类型,但没有返回类型推导。从 C++14 开始,您还可以使用 template&lt;typename T, typename U&gt; decltype(auto) foo(T t, U u) { return t + u; },它只是语法糖,但对于减少冗余非常有用。
    【解决方案2】:

    一种可能性是使用using 类型别名而不是typename。以下代码在我测试的编译器上编译(记得启用-std=c++11标志)。

    #include <type_traits>
    #include <iostream>
    
    // C++11
    template <typename T>
    using R = typename std::conditional<sizeof(T) == 4, char, short>::type;
    
    template <typename T>
    R<T> foo(T bar){return R<T>(bar);}
    
    int main() {
      std::cout << foo(13.0) << std::endl;
      return 0;
    }
    

    在 C++14 中,您可以使用 conditional_t trait,这更加简单。

    // C++14
    template <typename T>
    using R = std::conditional_t<sizeof(T) == 4, char, short>;
    

    【讨论】:

    • 它有效,但我不太喜欢这个解决方案,因为它引入了一个新的全局名称。如果这个R 模板本身很有用,那么这是一个很好的解决方案,但如果它只是为了节省一些函数声明的输入,我不愿意全局引入一个新的类型名称。绝对不是一个拥有如此常见/短名称的人。将帮助器类型放在它自己的命名空间中可以稍微缓解这个问题。
    • @YingXiong 我无法让它在 Visual Studio 2013 或 gcc 4.92 上运行。只需将其放入 main 作为测试代码应该会失败:std::cout &lt;&lt; foo(13.0) &lt;&lt; std::endl; gcc 说:“错误:无法将 'std::ostream {aka std::basic_ostream}' lvalue 绑定到 'std::basic_ostream &&'"
    • @JonathanMee 你是对的,我之前的测试用例无法编译,对不起。我更新了我的答案来解决这个问题——基本上你应该usingstd::conditional 特征的::type,而不是特征本身。另请注意上面@5gon12eder 的评论,我完全同意。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多