提升::变形建筑古怪 - 它的ctor接受一切

时间:2015-08-28 16:29:53

标签: c++ type-conversion boost-variant

boost-variant-ambiguous-construction question已触及该主题。

但我的问题不在于可以相互转换的类型,而是与完全不相关的类型。

简化示例:

// 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类型(D_optional)。

请参阅:

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

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

您可以在ideone上看到 - 很多编译器错误说它不知道您要打印boolABC_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:从这里要求   /usr/include/boost/variant/variant.hpp:1591:38:错误:没有匹配   调用'boost :: variant :: initializer :: initialize(void *,D&amp;)'的函数                  初始化初始化::(

此处ABC_variant的ostream运算符。

当然我知道为D / D_opt编写ostream运算符将解决问题 - 但问题在于诊断:如果boost :: variant不接受任何类型作为其构造函数的参数,编译器会告诉我简单的true - 不是这一堆误导性的句子......

我怀疑它是以这种方式设计 - 也许正在进行一些修复?

幸运的是我和ideone使用相同的编译器和boost:gcc4.9和boost1.58。

1 个答案:

答案 0 :(得分:1)

我创建了boost ticket for this problem。只是为了澄清什么是真正的问题:

真正的问题在于此boost.variant&#34;转换&#34;构造函数接受任何类型 - 没有限制,即使如此自然,如该参数类型应该可以转换为任何此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实例化的非模板函数。因此要么在某些结构类型中创建函数模板或者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

中修复