【问题标题】:declaring a template member function return type声明模板成员函数返回类型
【发布时间】:2015-08-18 03:12:34
【问题描述】:

我有一个简单的特征函数:

template <typename Traits>
struct Cal {
    typedef typename Traits::T T;
    static T f(T a, T b);
};

struct FTraits {
    typedef float T;
};
struct DTraits {
    typedef double T;
};

我能想到4种方法来实现Cal::f并指定返回类型。

// option 1. compile. as inline implementation
template <typename Traits>
struct Cal {
    typedef typename Traits::T T;
    static T f(T a, T b) {
        return a+b;
    }
};
// option 2. compile
template <typename Traits>
typename Traits::T Cal<Traits>::f(T a, T b) {
    return a+b;
};
// option 3. does not compile
template <typename Traits>
T Cal<Traits>::f(T a, T b) {
    return a+b;
};
// option 4. compile
template <typename Traits>
auto Cal<Traits>::f(T a, T b) -> T {
    return a+b;
};

我相信选项 4 是在 c++11 中添加的,因为选项 3 在以前的标准中是不可能的。我的问题是,为什么选项 3 不起作用?具体来说,我想知道返回类型 T 不能命名类型,而参数类型 T 可以命名类型背后的原因。编译器是否针对返回和参数类型在不同的上下文中工作?另外,为什么 c++11 选择选项 4 而不是选项 3?似乎选项 3 比选项 4 更直观。

【问题讨论】:

    标签: c++ typetraits


    【解决方案1】:

    即使是像 C++ 这样复杂语言的编译器仍然需要从头到尾处理文件。

    如果template&lt; … &gt; 之后的声明以T 开头,编译器需要知道T 是什么,以便解析它并确定它是一个返回类型,然后再继续查找声明的其余部分。

    本质上,限定符Cal&lt; Traits &gt;:: 需要在语法上出现在Cal 成员的任何非限定用法之前。使用尾随返回类型(将 Cal&lt; Traits &gt;:: 紧跟在 auto 之后)扩展语言比创建用于跳过具有未知标识符的类型名称的启发式方法要容易得多。

    【讨论】:

    • 所以返回类型很难推断,因为它是在函数签名和函数体之前指定的。在 c++11 中,尾随返回类型很容易推断,因为它是在函数签名之后指定的。我对么?然而,我记得 C++ 使用 LALR,因此能够提前看到一个标记 - 这是返回类型案例的函数签名。那么这种方式实现在技术上是否可行(肯定还是很难)?
    • @xosp7tom C++ 并未完全由其标准化中列出的语法规则定义;它只有 EBNF 和上下文相关的语义规则,用于由标识符形成的产品。一些编译器是“修改”的 LALR。在您的示例中,一个前瞻标记就足够了,但这不是一般情况。顺便说一句,扣除是另一回事;在您的示例程序中根本没有任何扣除。
    【解决方案2】:

    T 是 Cal 类模板中的 typedef。它不是在全局范围内定义的。以下应该可以作为选项 3 正常工作:

    template <typename Traits>
    typename Cal<Traits>::T Cal<Traits>::f(T a, T b) {
        return a+b;
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多