【问题标题】:Templated template argument name is invalid on the head of the method模板化的模板参数名称在方法的头部无效
【发布时间】:2019-11-14 10:14:49
【问题描述】:

我有以下示例代码:

template<int Size, template<typename Tin, int S> typename Cin, template<typename Tout, int S> typename Cout>
Cout<Tout, Size> SomeTemplatedMethod(const Cin<Tin, Size> &inputData) /* Here the definition fails on Tout and Tin as unknown. */
{
    Cout<Tout, Size> result; // Here Tout doesnt fail!
    //Whichever we do with inputData and result
    return result;
}

代码在方法的标头中失败,但在主体中没有! 我发现解决此问题的一种方法是这样做:

template<int Size, template<typename, int> typename Cin, template<typename, int> typename Cout, typename Tin, typename Tout>
Cout<Tout, Size> SomeTemplatedMethod(const Cin<Tin, Size> &inputData) /* Here the definition doesn't fail. */
{
    Cout<Tout, Size> result; // Here Tout doesnt fail!
    //Whichever we do with inputData and result
    return result;
}

但我绝对想使用第一种方式,因为它感觉更干净......

我正在使用 vc++14。我做错了什么?是错误还是预期行为?

谢谢!

【问题讨论】:

    标签: c++ templates c++14 template-argument-deduction template-templates


    【解决方案1】:

    这是预期的行为。

    来自[basic.scope.el]/1

    a 的模板参数名称的声明区域 template template-parameter 是最小的template-parameter-list,其中引入了名称。

    还有,来自[basic.scope.el]/3

    模板参数名称的潜在范围从它的位置开始 声明并在其声明区域的末尾结束。

    因此,例如的声明性区域Tin 在上面的第一个示例中是引入它的 template-parameter-list,其范围的结尾是该模板参数列表的结尾。你可以例如将Tin 用作template&lt; template&lt; typename Tin, Tin arg&gt; class Cin, ...,但不能使用Tin 声明超出其范围的名称。

    最后,请注意,对于 C++14 及更早版本,template&lt;...&gt; typename TT&gt; 是不合法的,因为模板模板参数声明可能只使用 class 关键字而不是 typename(您的示例应该也会失败)对于 C++14)。除非编译器扩展,在 C++14 中你需要使用 template&lt;...&gt; class TT&gt;。引用cppreference/template_parameters

    与类型模板参数声明不同,模板模板参数声明只能使用关键字class而不能使用typename。 (C++17 前)

    【讨论】:

      【解决方案2】:

      但我绝对想使用第一种方式,因为它感觉更干净......

      我知道这样更干净,但肯定不行,因为TinToutS 的声明范围仅限于CinCout 的声明。 (请参阅 dfri 的答案以获得更好的解释)。

      所以你必须在SomeTemplateMethod()的模板参数列表中声明TinTout(如Size)。

      您的第二个版本有效,但不是最佳的。

      请注意,您有五个模板参数(TinToutCinCoutSize)并且其中只有三个(CinTinSize)是可推断的(从参数的类型inputData)。

      所以你必须至少明确其中两个ToutCout

      如果您将ToutCout 放在第三和第五位,在模板参数列表中,就像在您的工作代码中一样,您必须显式显示所有五个模板参数,因此您必须调用函数如下

      MyCin<int, 42> mcin;
      
      auto mcout = SomeTemplatedMethod<42, MyCin, MyCout, int, float>(mcin);
      

      我建议将不可推导的模板参数放在前面,后面放置推导参数,例如(也使用 class 而不是 typename 声明模板模板参数;在 C++17 之前需要)

      template <typename Tout, template <typename, int> class Cout,
                typename Tin, template <typename, int> class Cin,
                int Size>
      Cout<Tout, Size> SomeTemplatedMethod (Cin<Tin, Size> const & inputData) 
      

      这样你只需要显式两个不可推导的参数

      MyCin<int, 42> mcin;
      
      auto mcout = SomeTemplatedMethod<float, MyCout>(mcin);
      

      以下是完整的编译示例(但我已将 int 更改为 std::size_t 的大小)

      #include <array>
      
      template <typename Tout, template <typename, std::size_t> class Cout,
                typename Tin, template <typename, std::size_t> class Cin,
                std::size_t Size>
      Cout<Tout, Size> SomeTemplatedMethod (Cin<Tin, Size> const &)
       {
         Cout<Tout, Size> result;
         return result;
       }
      
      int main ()
       {
         std::array<int, 42u> x;
      
         auto y = SomeTemplatedMethod<float, std::array>(x);
      
         static_assert( std::is_same<decltype(y), std::array<float, 42u>>::value,
                        "!" );
       }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-14
        • 1970-01-01
        • 1970-01-01
        • 2017-01-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多