作为构造函数参数的构造函数调用会将声明评估为函数指针

问题描述 投票:0回答: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 不应该警告我那里可能有问题吗?叮当声。

谢谢,

c++ constructor ambiguity
1个回答
1
投票

这被称为最令人烦恼的解析:尝试的声明被解析为函数声明。

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

有一些解决方法,例如编写

A a(( V(v) ))
,它不能被解析为带有
a
参数的函数
V
的声明并返回
A


关于警告,标准不要求对此进行任何诊断。毕竟,潜在的歧义已经解决了。有利于功能。 :-)

© www.soinside.com 2019 - 2024. All rights reserved.