Вызов конструктора в качестве параметра конструктора оценивает объявление как указатель на функцию

Я только что натолкнулся на странную двусмысленность, на которую у меня ушла целая вечность, так как она внезапно появилась в середине некоторого беспорядка шаблона после незначительного изменения 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) оценивает тип вместо объекта, почему A a(V(v), V(v)) не законно в 12?
  6. Забавно, что добавление скалярного значения также внезапно заставляет компилятор понять, что другой объект тоже в 8-11.
  7. Я пропустил какой-либо синтаксис, который воспроизвел бы двусмысленность? Знаете ли вы о каких-либо других запутанных случаях?
  8. Разве GCC не должен предупредить меня, что там может быть проблема? Clang делает.

Спасибо,

1

Решение

Это известно как самый неприятный разбор: попытка объявления анализируется как объявление функции.

Правило C ++: если что-то может быть проанализировано как объявление функции, так оно и будет.

Есть некоторые обходные пути, такие как написание A a(( V(v) )), который не может быть проанализирован как объявление функции a с V аргумент и возвращение A,


Что касается предупреждений, стандарт не требует какой-либо диагностики для этого. В конце концов, потенциальная неопределенность была решена. В пользу функции. 🙂

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector