2015-08-28 1 views
3

Тема затронута в этом boost-variant-ambiguous-construction question.boost :: вариант строения странности - его cтор принимает все

Но моя проблема не в том, что типы конвертируются друг в друга, но с совершенно несвязанными типами.

Упрощенный пример:

// types not related in any way 
class A {}; 
class B {}; 
class C {}; 
class D {}; 

using ABC_variant = boost::variant<A,B,C>; 
using D_optional = boost::optional<D>; 

Проблема была связана с тем, что дополнительно на какой-то тип не был для печати. Но совершенно не связанный оператор вывода для некоторого варианта пытался принять этот boost :: optional type (D_optional).

См:

std::ostream& operator << (std::ostream& os, const ABC_variant&) 
{ 
    return os << "ABC"; 
} 

int main() { 
    D_optional dopt; 
    std::cout << dopt; 
} 

Вы можете увидеть на ideone - множество компиляторов ошибок, говоря, что он не знает, что вы хотите напечатать bool или ABC_variant и в случае ABC_variant он не знает, как конвертировать D_optional - ABC_variant. Насколько я понимаю, boost :: optional конвертируется в bool, и первая альтернатива верна. Я понятия не имею, почему она пытается использовать ABC_variant конверсии ...

Кроме того, я упростил этот пример еще больше и отказался от boost :: optional :

int main() { 
    D d; 
    std::cout << d; 
} 

Теперь он не имеет "bool альтернативы" и просто жалуются, что он пытается построить ABC_variant из D:

prog.cpp:23:15: required from here /usr/include/boost/variant/variant.hpp:1591:38: error: no matching function for call to 'boost::variant::initializer::initialize(void*, D&)' initializer::initialize(

Th здесь является оператором ostream для ABC_variant.

Конечно, я знаю, что запись операционного оператора для D/D_opt решит проблему, но проблема связана с диагностикой: если boost :: variant не принимал никакого типа в качестве аргумента для своего конструктора, компилятор скажет мне просто true - не эта куча вводящих в заблуждение предложений ...

Я сомневаюсь, что это так по дизайну - возможно, некоторые исправления продолжаются?

К счастью, я и идеон используют один и тот же компилятор и boost: gcc4.9 и boost1.58.

+1

'optional' только * контекстуально * конвертируется в 'bool'. Что касается 'variant', этот конструктор должен быть ограничен, но это не так. –

ответ

1

Я создал boost ticket for this problem. Просто для выяснения, что представляет собой реальная проблема:

Настоящая проблема заключается в том, что этот конструктор boost.variant «преобразование» принимает любой тип - ограничений нет, даже так естественно, что этот тип аргумента должен быть конвертирован в любой из этих повышений. вариантные типы конкретизации:

template <typename T> 
variant(const T& operand) 
{ 
    convert_construct(operand, 1L); 
} 

Мое предложенное решение может быть что-то вроде этого:

template <typename T, typename ...C> 
struct IsAnyOf; 

template <typename T, typename ...C> 
struct IsAnyOf<T,T,C...> : std::true_type {}; 

template <typename T> 
struct IsAnyOf<T> : std::false_type {}; 

template <typename T, typename C1, typename ...C> 
struct IsAnyOf<T,C1,C...> : IsAnyOf<T, C...> {}; 

template <typename T, 
     typename EnableIf = typename std::enable_if<IsAnyOf<VariantType...>::value>::type> 
    variant(const T& operand) 

Но сейчас - единственное решение, чтобы не создавать какую-либо не функцию шаблона принимающую экземпляр повышения :: варианта. Поэтому либо создайте шаблон функции, либо агрегируйте экземпляр boost :: variant в каком-либо типе структуры.

Так как это:

template <typename T> 
typename std::enable_if<std::is_same<T,ABC_variant>::value, std::ostream&>::type 
operator << (std::ostream& os, const T&) 
{ 
    return os << "ABC"; 
} 

Или что-то вроде этого:

struct ABC_variant 
{ 
    boost::variant<A,B,C> v; 
    ABC_variant(const A&); 
    ABC_variant(const B&); 
    ABC_variant(const C&); 
}; 

issue фиксируется в boots.1.62

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