【问题标题】:When do we need a .template construct我们什么时候需要 .template 构造
【发布时间】:2011-03-30 18:30:23
【问题描述】:

我做了以下程序

#include <iostream>
#include <typeinfo>
template<class T>
struct Class
{
    template<class U>
    void display(){

        std::cout<<typeid(U).name()<<std::endl;
        return ;
    }

};


template<class T,class U>
void func(Class<T>k)
{
    k.display<U>(); 

}

int main()
{
    Class<int> d;
    func<int,double>(d);
}

上述程序无法编译,因为display() 是模板成员函数,因此必须在display() 之前进行.template 的限定。我说的对吗?

但是当我制作了以下程序时

#include <iostream>
#include <typeinfo>

template<typename T>
class myClass
{
    T dummy;
    /*******/
public:
    template<typename U>
    void func(myClass<U> obj);

};

template<typename T>
template<typename U>

void myClass<T>::func(myClass<U> obj)
{
    std::cout<<typeid(obj).name()<<std::endl;
}
template<class T,class U>
void func2(myClass<T>k)
{
    k.template func<U>(k); //even it does not compile

}
int main()
{
    myClass<char> d;
    func2<char,int>(d);
    std::cin.get();
}

为什么k.func&lt;char&gt;(k); 在给出.template 构造后仍无法编译?

【问题讨论】:

  • 可以在 Comeau C++ 模板常见问题解答条目"What is the -&gt;template, .template and ::template syntax about?" 中找到此问题的完整答案。
  • 我被卡住了... §5.2.5/1 说“后缀表达式后跟一个点 . 或箭头 ->,可选地后跟关键字模板 (14.8.1),然后是一个 id 表达式,是一个后缀表达式。”但是 14.8.1 似乎是无关的,除了描述 C++ 如何能够解析成员函数模板没有关键字。这个关键字在哪里指定?
  • @Potatoswatter:关键字在 §2.11 表 3 中指定,当然。 ;-)(更严肃地说,这是一个好问题)。

标签: c++ templates member-functions


【解决方案1】:

&lt; 符号表示“小于”和“开始模板参数”。为了区分这两种含义,解析器必须知道前面的标识符是否命名了一个模板。

例如考虑代码

template< class T >
void f( T &x ) {
    x->variable < T::constant < 3 >;
}

T::variableT::constant 必须是模板。该函数的含义不同,具体取决于哪个是哪个不是:

  1. T::constant 与 3 进行比较,布尔结果成为 T::variable&lt;&gt; 的模板参数
  2. T::constant&lt;3&gt;x-&gt;variable 进行比较。

为了消除歧义,template 关键字必须位于 variableconstant 之前。案例一:

template< class T >
void f( T &x ) {
    x->template variable < T::constant < 3 >;
}

案例 2:

template< class T >
void f( T &x ) {
    x->variable < T::template constant < 3 >;
}

如果关键字仅在实际模棱两可的情况下(这种情况很少见)才需要,那就太好了,但它使解析器更容易编写,并且可以防止此类问题让您措手不及。

对于标准语,请参阅 14.2/4:

当成员模板的名称 专业化出现在 之后。或-> 在后缀表达式中或之后 嵌套名称说明符 合格的 id 和 后缀表达式或限定 ID 显式地依赖于 模板参数(14.6.2), 成员模板名称必须加前缀 通过关键字模板。否则 假定名称为 a 非模板。

【讨论】:

  • +1 对于第一个示例:这是一个非常棒的代码 sn-p,用于演示 C++ 语法的上下文敏感性以及为什么需要这些关键字。
  • 结束时的歧义怎么办>?例如案例x-&gt;foo &lt; T::bar &gt; (3) &gt; (4);
  • @AjayBrahmakshatriya 为此,有 typename 关键字。
  • @Potatoswatter 我不确定 typename 在这里会有什么帮助。假设已知T::barint 类型,而foo 采用int 类型的模板参数。目前尚不清楚模板参数是T::bar &gt; (3) 和带有参数(4) 的调用,还是模板参数是T::bar 而参数是(3)。然后将调用结果与(4)进行比较。
  • @AjayBrahmakshatriya 如果它是任何类型,则表达式具有语法优先级并且 > 是一个运算符。仅当使用 typename 时,> 才是分隔符。
【解决方案2】:

C++ Templates 的第 5.1 节详细解释了这个结构

下面的函数有问题

template<class T,class U> 
void func2(myClass<T> k) 
{ 
    k.template func<U>(k); //even it does not compile 

} 

这里 T = char 和 U = int

myclass<char>::func<int>(myclass<char>) 

正在被调用。但是这样的功能是不存在的

即使在正常情况下 'char' 可以转换为 'int',这对于显式指定的模板参数并不适用

【讨论】:

  • 这似乎是真正的答案。
【解决方案3】:

标准要求templatetypename 关键字到disambiguate things that depend on the template context

【讨论】:

    【解决方案4】:

    第一个示例在 VS 2010 中编译并运行良好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-27
      • 1970-01-01
      • 2019-07-17
      • 1970-01-01
      • 2019-03-01
      • 1970-01-01
      相关资源
      最近更新 更多