【问题标题】:Constraints on explicit specialization of a member of a class template对类模板成员显式特化的约束
【发布时间】:2019-01-21 02:26:05
【问题描述】:

根据[temp.expl.spec]/16:

类模板的成员或成员模板可以显式专门用于类模板的给定隐式实例化...

经过一些测试,我发现特化应该与类模板的隐式实例化中的成员匹配,这意味着它们应该是相同的类型。例如,

template<class T> struct A {
  void f(T);
  static T i;
};

template<> void A<int>::f(int);     // ok 
// template<> void A<int>::f(char); // error

template<> int A<int>::i;     // ok
// template<> char A<int>::i; // error

标准在哪里指定了此类约束?

【问题讨论】:

  • 如果template&lt;class T&gt;和void f(T)中有相同的 T,那么Ts怎么可能不同?
  • 除了 Evgeny:为类型 int 实例化 struct A,您还定义了一个方法 void f(int);。如果你想实现template&lt;&gt; void A&lt;int&gt;::f(char) { } - 在struct A&lt;int&gt; 中没有定义这样的方法。如果你需要这个,你必须完全专门化template &lt;class T&gt; struct A,例如template &lt;&gt; struct A&lt;int&gt; { void f(char); }; 现在,您可以(必须)实现void A&lt;int&gt;::f(char) { }。替代方案:将 quest 中的方法设为自己的模板:template &lt;class T&gt; struct A { template &lt;class U = T&gt; void f(U); }。
  • 方法f(T) 本身不是模板——它是template struct A 的一部分。你不能专门化不是模板的东西,对吧。 (对不起,这也不是“语言律师”评论。)
  • 请记住,模板的最初想法是将类型设置为参数。在每次出现时插入任意类型并不是一个纯粹的占位符。
  • 您不能专门化非模板。 (......我可以想象你在标准中找不到任何引用。)只是你可以专门化模板(而不是别的)。

标签: c++ templates language-lawyer template-specialization


【解决方案1】:

正如 Evgeny 的评论中指出的那样:

为类型int 实例化struct A,您会得到一个定义的方法void f(int);。

如果你想实现template&lt;&gt; void A&lt;int&gt;::f(char) { }——struct A&lt;int&gt; 中没有定义这样的方法。

要实现这一点,您可以将整个 struct A 专门化为 int。

另一种方法是(如 answer of user846834 中所示)将 quest 中的方法本身设为模板。

示例代码:

#include <iostream>

template <class T>
struct A {
  void f(T);
};

template <>
void A<int>::f(int) { std::cout << "void A<int>::f(int) called.\n"; }
#if 0 // ERROR
void A<int>::f(char) { std::cout << "void A<int>::f(char) called.\n"; }
#endif // 0

template <class T>
struct B {
  void f(T);
};

template <>
struct B<int> {
  void f(char);
};

void B<int>::f(char) { std::cout << "void B<int>::f(char) called.\n"; }

template <class T>
struct C {
  template <class U = T>
  void f(U) { std::cout << "void C<T>::f(U) called.\n"; }
};

template <> template <>
void C<int>::f(char) { std::cout << "void C<int>::f(char) called.\n"; }

int main()
{
  A<int> a; a.f(0);
  B<int> b; b.f(0);
  C<int> c; c.f('0');
  // done
  return 0;
}

输出:

void A<int>::f(int) called.
void B<int>::f(char) called.
void C<int>::f(char) called.

Live Demo on coliru

【讨论】:

    【解决方案2】:

    在您给出的链接示例中,只有非类型模板参数 (X1, X2) 被指定为与 T 不同的类型。 只有它们可以被指定为不同的。类型模板参数需要和特化一样。

    template<class T> struct A {
      void f(T);
      template<class X1> void g1(T, X1);
      template<class X2> void g2(T, X2);
      void h(T) { }
    };
    
    // member template specialization
    template<> template<>
      void A<int>::g1(int, char);           // X1 deduced as char
    template<> template<>
      void A<int>::g2<char>(int, char);     // X2 specified as char
    

    【讨论】:

    • 为什么类型模板参数(更一般地,一个成员的类型)需要和特化一样?
    猜你喜欢
    • 2011-07-27
    • 1970-01-01
    • 2015-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多