2012-02-03 25 views
1

我在这个网址如果T是一个模板参数,T :: x(y)语句是如何模糊的?

http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fkeyword_typename.htm

读取事实表,我意识到,我不知道什么类型的T :: X可能代表可能。下面是摘录

template<class T> class A 
{ 
    T::x(y); 
    typedef char C; 
    A::C d; 
} 

声明T :: X(Y)是模糊的。它可能是一个调用函数x() 与非本地参数y,或者它可能是一个变量y 类型T :: x的声明。 C++将把这个语句解释为一个函数调用。 为了使编译器将此语句解释为 声明,您需要将关键字typename添加到它的开头 。声明A :: C d;是不合格的。 A类也指 A,因此取决于模板参数。您必须在 关键字类型名称添加到这个声明的开头:

我想了解如何有可能是类型T :: x的变量y,怎么会变成这样的工作,有什么能这可能意味着什么? x会是什么?

感谢:-)

回答

6

作为热身到我的完整的答案,考虑以下因素:

template <typename T> void IterateOverContainer(T container) { 
    /* Error! */ 
    T::iterator itr(container.begin()); 
} 

这里,iterator是嵌套的T内部的类型;例如,std::vector<int>::iterator。为了避免歧义这里,typename关键字成为必要:

template <typename T> void IterateOverContainer(T container) { 
    /* Now good! */ 
    typename T::iterator itr(container.begin()); 
} 

现在,这是“明确”一类的名称(这是typename手段!),所以很明显,我们要声明一个变量,而不是通话一个函数。

这就是说,新的C++ 11层的功能,你可以用auto完全回避这个问题:

template <typename T> void IterateOverContainer(T container) { 
    auto itr(container.begin()); 
} 

,或者更明确:

template <typename T> void IterateOverContainer(T container) { 
    auto itr = container.begin(); 
} 

现在,你的问题:如何可以T::x(y)曾经声明一个变量?好了,由于到C的一个奇怪的怪癖,这是一个完全合法的变量声明:

int (x); 

这是一样

int x; 

因此,如果我们有这样的事情:

template <typename T> void IterateOverContainer(T container) { 
    /* Error! */ 
    T::iterator(itr); 
} 

这可以解释为T::iterator类型的名为itr的变量的声明,或者作为对函数T::iterator的呼叫通过itra是一个参数。 typename的使用消除了它是哪一个。

有趣的是,这个额外括号的规定与Most Vexing Parse存在的原因相同。我希望你永远不会遇到它。 :-)

希望这有助于!

+0

看起来像你的帐户是为了回答这个问题:) – 2012-02-03 03:50:37

+0

只是几个简单的问题,如果我在另一个内部定义一个类(x内部的Y)这将是类型Y :: x?我认为小写字母x是把我扔掉的东西,我没有意识到这是一个嵌套类,如果它是什么。也是T :: iterator itr(container.begin()); 构建一个类型,如何解释? Sry因为我对这个话题的无知 – rubixibuc 2012-02-03 03:53:00

+0

@ rubixibuc-(请注意,在我收到这条消息之前,我已经更新了我的答案,所以你可能想阅读结束我的编辑)。我不确定我是否通过“构建一个类型”来获得你的意思。你能澄清吗? – templatetypedef 2012-02-03 03:54:44

0

如已经陈述的,T::x可以指“该x类型(可能是一个或classtypedef),其内T定义。它也可以指”一个指针T的成员函数x

编译器通常可以根据某些线索找出哪个是正确的(您是否写过T::x foovoid (T::*)() foo = T::x?); Visual Studio,和GCC曾经(他们停下来,因为当时,人们会让他们的代码在GCC上编译,但不在Visual Studio上编译)。该标准要求typename消除疑难案件。

相关问题