boost::variant 构造怪异 - 它的 ctor 接受一切
boost::variant construction weirdness - its ctor accepts everything
此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 上看到 - 大量编译器错误表明它不知道您要打印什么 bool
或 ABC_variant
并且在 [=15= 的情况下] 它不知道如何将 D_optional
转换为 ABC_variant
。据我了解 boost::optional 可以转换为 bool
并且第一个选择是正确的我不知道为什么它会尝试使用 ABC_variant
转换...
此外,我进一步简化了这个例子并放弃 boost::optional:
int main() {
D d;
std::cout << d;
}
现在,它没有“bool
替代方案”,只是抱怨它试图从 D
:
构造 ABC_variant
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(
此处 是 ABC_variant
的 ostream 运算符。
当然我知道为 D/D_opt 编写 ostream 运算符将解决问题 - 但问题在于诊断:如果 boost::variant 不接受任何类型作为其构造函数的参数,编译器会告诉我简单的真实 - 而不是这一堆误导性的句子...
我怀疑这是设计使然 - 也许正在进行一些修复?
幸好我和ideone用的是同一个编译器和boost:gcc4.9和boost1.58。
我创建了boost ticket for this problem。只是为了澄清真正的问题是什么:
真正的问题是这个 boost.variant "converting" 构造函数接受任何类型 - 没有限制,即使像参数类型那样自然也应该可以转换为任何这个 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
此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 上看到 - 大量编译器错误表明它不知道您要打印什么 bool
或 ABC_variant
并且在 [=15= 的情况下] 它不知道如何将 D_optional
转换为 ABC_variant
。据我了解 boost::optional 可以转换为 bool
并且第一个选择是正确的我不知道为什么它会尝试使用 ABC_variant
转换...
此外,我进一步简化了这个例子并放弃 boost::optional:
int main() {
D d;
std::cout << d;
}
现在,它没有“bool
替代方案”,只是抱怨它试图从 D
:
ABC_variant
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(
此处 是 ABC_variant
的 ostream 运算符。
当然我知道为 D/D_opt 编写 ostream 运算符将解决问题 - 但问题在于诊断:如果 boost::variant 不接受任何类型作为其构造函数的参数,编译器会告诉我简单的真实 - 而不是这一堆误导性的句子...
我怀疑这是设计使然 - 也许正在进行一些修复?
幸好我和ideone用的是同一个编译器和boost:gcc4.9和boost1.58。
我创建了boost ticket for this problem。只是为了澄清真正的问题是什么:
真正的问题是这个 boost.variant "converting" 构造函数接受任何类型 - 没有限制,即使像参数类型那样自然也应该可以转换为任何这个 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