2014-08-20 2 views
2

У меня есть проблемы с помощью следующей конструкции:подталкивания list_of с аргументами по умолчанию

struct A { 
    int min_version; 
    int max_version; 
    std::vector<int> nodes; 

    A(std::vector<int> _nodes, int _min_version = 0, int _max_version = MAXINT) 
     : nodes(_nodes), min_version(_min_version), max_version(_max_version) 
    {}; 

    }; 

    static std::vector<A> a = list_of<A> 
    (list_of (1) (2)) 
    ; 

я получаю ошибку компиляции, что ни один из 2-х перегрузок не может конвертировать все типы аргументов (Visual Studio 2013). Однако, когда я добавляю значение для аргументов один или оба по умолчанию, он отлично компилируется:

static std::vector<A> a = list_of<A> 
    (list_of (1) (2), 1) 
    ; 

Итак, что же трюк, чтобы сделать аргументы как по умолчанию работает?

ответ

1

Проблема с версией одним аргументом становится намного более очевидным, когда вы замените list_of<A>(...) на list_of(A(...)): ошибка компилятора их становится (GCC):

 
list.cc: In function ‘int main()’: 
list.cc:18:30: error: call of overloaded ‘A(boost::assign_detail::generic_list<int>&)’ is ambiguous 
    list_of (A (list_of (1) (2))); 
          ^
list.cc:18:30: note: candidates are: 
list.cc:11:3: note: A::A(std::vector<int>, int, int) 
    A(std::vector<int> _nodes, int _min_version = 0, int _max_version = INT_MAX) 
^
list.cc:6:8: note: A::A(const A&) 
struct A { 
     ^
list.cc:6:8: note: A::A(A&&) 

И это имеет смысл, вроде: общий нетипизированным список * претензий быть конвертируемым в любой тип; он не (и, вероятно, не может) использовать SFINAE для отклонения типов, для которых преобразование не будет работать.

В вашем примере преобразование из нетипизированного списка в A является лучшим совпадением, чем преобразование из нетипизированного списка в std::vector<int> в A. Это преобразование, конечно, не работает.

Когда вы передаете второй аргумент, компилятор знает, что вы не можете пытаться вызвать конструктор копирования.

Мое личное предпочтение было бы добавить фиктивный аргумент конструктора, аналогично использованию стандартной о piecewise_construct_t:

struct from_vector { }; 
struct A { 
    ... 
    A(std::vector<int> _nodes, ...) { ... } 
    A(from_vector, std::vector<int> _nodes, ...) : this(_nodes, ...) { } 
}; 

Вы можете написать

list_of<A>(from_vector(), list_of (1) (2)) 

* Когда я скажем, «нетипизированный список», я, конечно, понимаю, что Boost фактически определил тип для этого списка и что выражения C++ всегда имеют тип.

+0

Это замечательный. Но после вашего объяснения это действительно имеет смысл. Тем не менее, для меня загадка, как неправильный вывод может быть лучшим, если существует очевидный. –

+0

@MikeLischke Проблема в том, что неправильный еще более очевидный, чем тот, который вы хотите. По существу, у вас есть 'struct A {template оператор T(); } ',' struct B {} 'и' struct C {C (B); } '. Основываясь только на объявлениях, когда у вас есть 'A', и вы хотите' C', наиболее очевидным способом получить его является вызов оператора преобразования шаблонов. Будет ли это действительно работать, неизвестно, есть ли у вас просто объявления. То, что вы хотите, конструктор 'C (B)' после использования оператора преобразования шаблонов для получения 'B', является только вторым самым очевидным способом. Тем не менее ... – hvd

+0

... Я думаю, что я ошибался в предположении, что SFINAE будет невозможно. В этом случае это просто плохой дизайн 'list_of', и он * может * альтернативно быть спроектирован таким образом, чтобы ваш код работал, я теперь думаю. Но так как это не так, вы застряли над проблемой. – hvd

Смежные вопросы