2013-05-16 9 views
0

У меня есть boost::variant по множеству конструктивных (и, возможно, даже непередвигаемых/не копируемых и не копируемых/перемещаемых) классов по умолчанию, имеющих существенные разные прототипы конструкторов, отличных от стандартного , как показано ниже:push to list of boost :: variant's

#include <boost/variant.hpp> 
#include <string> 
#include <list> 

struct A { A(int) { ; } }; 
struct B { B(std::string) { ; } }; 
struct C { C(int, std::string) { ; } }; 

using V = boost::variant< A const, B const, C const >; 
using L = std::list<V>; 

int main() 
{ 
    L l; 
    l.push_back(A(1)); // an extra copy/move operation 
    l.push_back(B("2")); // an extra copy/move operation 
    l.push_back(C(3, "3")); // an extra copy/move operation 
    l.emplace_back(4); 
    l.emplace_back(std::string("5")); 
    // l.emplace_back(3, std::string("3")); // error here 
    return 0; 
} 

Я ожидаю, что std::list::emplace_back позволяет мне строить и вставки (в одной операции) новых объектов (всех A, B, C типов) в список, даже если у них есть T & operator = (T const &) = delete;/T & operator = (T &&) = delete; и T(T const &) = delete;/T(T &&) = delete;. Но что мне делать, если конструктор не является конверсионным? То есть имеют более одного параметра. Или что мне делать, если у двух разных типов базиса есть неоднозначные прототипы конструктора? На мой взгляд, это дефект реализации библиотеки boost::variant в свете новых возможностей стандарта C++ 11, если любой из них может быть применен для решения проблемы.

Я специально спросил о std::list и boost::variant в суперпозиции, потому что они оба внутренне реализовать Pimpl идиомы в той или иной форме, насколько я знаю (скажем, boost::variant в настоящее время разработаны с помощью temporary heap backup approach).

+0

Вам нужен контейнер и 'emplace', чтобы увидеть эту проблему? Предположительно, проблема двусмысленности, например. может возникнуть просто с простой конструкцией «boost :: variant». Что происходит с 'V v (3, std :: string (" 3 "));'? –

+0

'V v (3, std :: string (" 3 "));' приводит к ошибке 'no matching function для вызова to boost :: variant :: variant (int , std :: string) ''' note: шаблон аргумент вычет/замещение не удалось' примечание: кандидат ожидает 1 аргумент, 2 предоставлен' – Orient

+0

. Ваше предположение верно. Я просто проиллюстрировал пример реального контекста. 'std :: list' не является обязательным. – Orient

ответ

1

emplace может вызывать только конструкторы соответствующего типа. И конструкторы boost::variant принимают только отдельные объекты, которые однозначно конвертируются в один из вариантов варианта.

variant не передает параметры произвольно одному из своих ограниченных типов. Это просто имеет значение. A single Значение, которое будет пытаться преобразовать в один из ограниченных типов.

Так что вам нужно будет построить объект, а затем скопировать его в variant.

+0

Но что мне делать, если мой тип не копируется/перемещается и не копируется/перемещается? – Orient

+0

Я думаю, что 'std :: is_constructible' и некоторая метапрограммирующая магия могут помочь реализовать такой конструктор для' boost :: variant' дизайнеров. – Orient

+1

@Dukales: "* Но что мне делать, если мой тип не копируется/перемещается и не копируется/перемещается? *« Тогда вы не можете использовать его в варианте. Что касается возможности создания таких конструкторов, это возможно, но это, безусловно, не существует для 'boost :: variant' * прямо сейчас *. –

1

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