2013-04-11 112 views
1

我刚刚遇到了一个奇怪的含糊不清的问题,这个问题花了我很多时间来隔离,因为它在API更改后突然出现在某些模板混乱的中间。作为构造函数参数的构造函数调用将声明作为函数指针进行评估

以下示例探讨调用构造函数的不同方法(或者我认为的),其中一些对我来说很模糊。在他们所有人中,我试图声明A类型的对象。

#include <vector> 
#include <cstdlib> 
#include <iostream> 
#include <typeinfo> 
using namespace std; 

// just a dummy class to use in the constructor of the next class 
struct V { 
    V(const std::vector<size_t> &){} 
}; 

// the class we are interested in 
struct A{ 
    A(const V &){} 
    A(int, const V &){} 
    A(const V &, int){} 
    A(const V &, const V &){} 
}; 

// a dummy function to delegate construction of V 
V buildV(std::vector<size_t> &v){ return V(v); } 

int main(){ 
    std::vector<size_t> v = {1024,1024}; 
    V vw(v); 

    // I am using macros to make the constructor argument more visible 
    #define BUILD_A(X) { A a(X); std::cerr << typeid(a).name() << std::endl; } 
    #define BUILD_A2(X,Y) { A a(X, Y); std::cerr << typeid(a).name() << std::endl; } 

    // All of the following call the constructor of A with different parameters 
    // the comment on the right shows the type of the declared a 
    /* 1 */ BUILD_A(vw)      // object 
    /* 2 */ BUILD_A(V(v))      // function pointer 
    /* 3 */ BUILD_A(v)      // object 
    /* 4 */ BUILD_A(std::vector<size_t>()) // function pointer 
    /* 5 */ BUILD_A((V)V(v))     // object 
    /* 6 */ BUILD_A((V(v)))     // object 
    /* 7 */ BUILD_A(buildV(v))    // object 

    /* 8 */ BUILD_A2(10,V(v))     // object 
    /* 9 */ BUILD_A2(V(v),10)     // object 
    /* 10 */ BUILD_A2(vw,V(v))     // object 
    /* 11 */ BUILD_A2(V(v), vw)     // object 

    /* 12 */ //BUILD_A2(V(v), V(v))    // doesn't compile 
    /* 13 */ BUILD_A2(V(v), (V)V(v))   // object 
} 

第二和第四实施例似乎声明一个函数指针,而不是一个对象,这引起了几个问题:

  1. 为什么V(v)解释为类型,而不是为A a(V(v))对象?
  2. 如何解析V(v)(V)V(v)解释不同?
  3. 为什么编译器无法推断出演员本身?
  4. 6中的双括号((...))是否具有语义含义,还是仅仅有助于消歧解析器?我不明白这可能是一个优先问题。
  5. 如果V(v)的计算结果为Type而不是对象,为什么A a(V(v), V(v))在12中不合法?
  6. 有趣的是,添加一个标量值突然让编译器意识到另一个对象也在8到11之间。
  7. 我是否错过任何会重现歧义的语法?你知道任何其他令人困惑的情况吗?
  8. 不应该GCC警告我那里可能有问题吗?铿锵。

感谢,

+0

请参阅http://en.wikipedia.org/wiki/Most_vexing_parse – JBentley 2013-04-11 19:05:29

回答

1

这就是所谓的最棘手的解析:尝试的声明被解析为函数声明。

C++规则是,如果某些东西可以被解析为一个函数声明,它将会是。

有一些变通办法,如写作A a((V(v))),不能被解析为一个功能a的一个V参数并返回A声明。


关于警告,标准不需要任何诊断。毕竟,潜在的不明确性已经解决。赞成功能。 :-)

+0

这解释了我的大部分观点。我仍然不确定为什么'A a(V(v),V(v))'也不合法。难道它不是一个带两个无名参数的函数吗? – Thibaut 2013-04-20 14:58:13