【问题标题】:Template method of template class specialization模板类特化的模板方法
【发布时间】:2012-02-14 11:54:32
【问题描述】:

这是我的代码:

template<typename T1, typename T2> class MyClass
{
public:
    template<int num> static int DoSomething();
};

template<typename T1, typename T2> template<int num> int MyClass<T1, T2>::DoSomething()
{
    cout << "This is the common method" << endl;
    cout << "sizeof(T1) = " << sizeof(T1) << endl;
    cout << "sizeof(T2) = " << sizeof(T2) << endl;
    return num;
}

效果很好。但是当我尝试添加这个

template<typename T1, typename T2> template<> int MyClass<T1, T2>::DoSomething<0>()
{
    cout << "This is ZERO!!!" << endl;
    cout << "sizeof(T1) = " << sizeof(T1) << endl;
    cout << "sizeof(T2) = " << sizeof(T2) << endl;
    return num;
}

我得到编译器错误: «>» 标记之前的无效显式特化 «int MyClass::DoSomething()» 的模板 ID «DoSomething» 与任何模板声明都不匹配

我使用 g++ 4.6.1 我该怎么办?

【问题讨论】:

    标签: c++ linux templates g++


    【解决方案1】:

    不幸的是,如果不专门化外部模板,就无法专门化属于类模板成员的模板:

    C++11 14.7.3/16:在类模板的成员或出现在命名空间范围内的成员模板的显式特化声明中,成员模板及其一些封闭类模板可能保持未特化,除非声明不能明确地特化类成员模板,如果它的封闭类模板也没有显式特化。

    我认为您最好的选择是将额外参数添加到MyClass,然后对其进行部分专门化。

    【讨论】:

    • 但是这个例子并没有明确地特化一个类成员模板——它特化了一个函数成员模板。因此,您突出显示的部分不适用,并且句子前一部分中给出的许可似乎适用。
    • @AlanStokes:“类成员模板”是指作为类成员的模板——它可以是函数或嵌套类的模板。 “成员类模板”将专门指作为成员的类模板(根据 14.7.3/1 中该术语的使用)。至少 GCC 使用了这种解释。
    • 14.5.2/1 建议作为类成员的模板只是“成员模板”。 “类成员模板”似乎不是一个定义的术语。呸。但看起来DR 529 会澄清这一点以同意您的回答。
    • 有谁知道这是为什么?我找到了一堆解释,只是解释你做不到,但没有提到任何理性。
    【解决方案2】:

    老问题,我知道,

    但我在当前项目中偶然发现了同样的问题,并找到了一种解决方法,该解决方法至少对模板参数有效,模板参数不是类型而是值(如template &lt;int num&gt;)。

    我的解决方案的实现:

    template<class T> template<int num> void Classname<T>::methodname()
    {
        if (num == 0)
        {
            //implementation for num == 0
        }
        else if (num == 1)
        {
            //implementation for num == 1
        }
        //more cases...
    }
    

    num == constant 将评估为一个常量表达式,因此编译器将优化您的代码,以便为每种情况保持正确的实现。

    如果我错了,或者如果有什么东西使它成为一个不好的解决方案,请纠正我;)

    【讨论】:

      【解决方案3】:

      这很可悲,但却是事实:你不能显式特化一个类模板,除非它的封闭类模板也被显式特化。有关更多信息,您可以阅读

      下面我先专门化了 MyClass,一切都搞定了。

      #include <iostream>
      using namespace std;
      
      template<typename T1, typename T2> class MyClass
      {
      public:
        template<int num> static int DoSomething();
      };
      
      template<typename T1, typename T2> template<int num> int MyClass<T1, T2>::DoSomething()
      {
        cout << "This is the common method" << endl;
        cout << "sizeof(T1) = " << sizeof(T1) << endl;
        cout << "sizeof(T2) = " << sizeof(T2) << endl;
        return num;
      }
      
      template<> template<> int MyClass<char, int>::DoSomething<0>()
      {
        cout << "This is ZERO!!!" << endl;
        cout << "sizeof(T1) = " << sizeof(char) << endl;
        cout << "sizeof(T2) = " << sizeof(int) << endl;
        return 0;
      }
      
      int main() {
        MyClass<char, int> m;
        m.DoSomething<2>();
        m.DoSomething<0>();
        return 0;
      }
      

      输出:

      This is the common method
      sizeof(T1) = 1
      sizeof(T2) = 4
      This is ZERO!!!
      sizeof(T1) = 1
      sizeof(T2) = 4
      

      尤里卡!这在 MSVCPP 10 上运行良好。

      #include <iostream>
      using namespace std;
      
      template<typename T1, typename T2> class MyClass
      {
      public:
        template<int num> static int DoSomething();
        template<> static int DoSomething<0>() {
          cout << "This is ZERO!!!" << endl;
          cout << "sizeof(T1) = " << sizeof(T1) << endl;
          cout << "sizeof(T2) = " << sizeof(T2) << endl;
          return 0;
        }
      };
      
      template<typename T1, typename T2> template<int num> int MyClass<T1, T2>::DoSomething()
      {
        cout << "This is the common method" << endl;
        cout << "sizeof(T1) = " << sizeof(T1) << endl;
        cout << "sizeof(T2) = " << sizeof(T2) << endl;
        return num;
      }
      
      int main() {
        MyClass<char, int> m;
        m.DoSomething<2>();
        m.DoSomething<0>();
        return 0;
      }
      

      输出:

      This is the common method
      sizeof(T1) = 1
      sizeof(T2) = 4
      This is ZERO!!!
      sizeof(T1) = 1
      sizeof(T2) = 4
      

      顺便说一句,不要从专业化中return num;。它永远不知道num 是什么。

      【讨论】:

      • @MikeSeymour 好的。但它确实适用于 MSVCPP 10。
      • @DaddyM:MSVC 不强制执行某些标准规则。尤其是模板编程,这很糟糕。我总是在 MingW 中编写复杂的模板部分,如果可以编译,则将其移至 MSVC。
      • MSVC 具有针对课堂成员专业化的扩展
      【解决方案4】:

      类似于 DocValle 的答案,不依赖可能的编译器优化

      你可以使用 constexpr if 来强制执行编译时分支

      template<class T> template<int num> void Classname<T>::methodname()
      {
          if constexpr (num == 0)
          {
              //implementation for num == 0
          }
          else if constexpr (num == 1)
          {
              //implementation for num == 1
          }
          //more cases...
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-12-24
        • 2010-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多