我已经暂时使用boost::variant
,但仍有一些问题令我感到困惑。
以下代码未编译,因为我正在尝试将std::pair<int, int>
存储到boost::variant
,该int
只能包含double
,std::string
和{{1} }}。我仍然需要函数convert
,但它应该抛出一个异常,以防我试图在boost::variant
中存储一个它不适合的类型。
#include <iostream>
#include <boost/variant.hpp>
#include <vector>
typedef boost::variant<int, double, std::string> TVar;
template<typename T>
std::vector<TVar> convert(const std::vector<T>& vec) {
std::vector<TVar> ret;
for (size_t t = 0; t < vec.size(); t++) {
ret.push_back(vec[t]);
}
return ret;
}
int main(int arg, char** args) {
{
std::vector<double> v = { 3,6,4,3 };
auto ret=convert(v);
std::cout << ret.size() << std::endl;
}
{
std::vector<bool> v = { true, false, true };
auto ret=convert(v);
std::cout << ret.size() << std::endl;
}
{
std::vector<std::pair<int, int>> v = { std::make_pair<int, int>(5,4) };
auto ret = convert(v);
std::cout << ret.size() << std::endl;
}
return 0;
}
似乎std::enable_if
可能是解决方案的一部分,但我无法将其结束。
答案 0 :(得分:4)
以下代码未编译,因为我试图将
std::pair<int, int>
存储到boost::variant
,只能包含int
,double
和{ {1}}。我仍然需要函数convert,但它应该抛出异常,以防我试图在std::string
中存储一个它不适合的类型。
这实际上并不是你想要的东西,你应该对你的行为感到高兴。
如果你试图在boost::variant
中存储一个它不适合的类型,那么程序中的一个问题在编译时对编译器来说是显而易见的 - 编译器不知道如何为了继续进行操作,根本没有合理的代码可供它发射。它知道您要存储的类型,它知道您拥有哪种变体,并且可以看到没有转换。
当编译器拒绝代码并告诉您没有转换时,它会在得知问题后立即告诉您该问题。
如果只是在尝试转换时在运行时抛出异常,那么这意味着在测试之后才会发现问题。这更令人烦恼和昂贵 - 这意味着编译器知道或应该知道转换错误的问题,但决定将其掩盖起来。
通常在C ++中,程序员会尝试编写代码,以便任何常见错误都会显示为编译时错误,而不是运行时错误,因此。 boost::variant
写下了这个想法。
所以,我认为你应该重新审视这个问题的前提,并尝试解释你实际上想要做什么。
答案 1 :(得分:1)
这是我的方法,使用SFINAE。这不是最佳解决方案,因为每次从TVar
添加/删除类型时都必须更改测试,但它有效:
//Using SFINAE to check if type can be converted into TVar
template<typename T, typename = std::enable_if_t<std::is_same<TVar::types::item, T>::value
|| std::is_same<TVar::types::next::item, T>::value
|| std::is_same<TVar::types::next::next::item, T>::value>>
std::vector<TVar> convert(const std::vector<T>& vec) {
std::vector<TVar> ret;
for (size_t t = 0; t < vec.size(); t++) {
ret.push_back(vec[t]);
}
return ret;
}
std::vector<std::nullptr_t> convert(...)
{
//throw Something
return{};
}
小解释:
boost::variant
有一个内部类型,名为types
。它基本上是一个编译时链表,每个元素的类型都在type
中。
std::enable_if_t
的条件是
std::is_same<TVar::types::item, T>::value /*is T same as the first type in variant? */
|| std::is_same<TVar::types::next::item, T>::value /* is T same as second type */
|| std::is_same<TVar::types::next::next::item, T>::value /* is T same as third type */
因此,模板convert
仅在上述条件之一为true
时才会被采用,而boost::variant
中的类型则为domain1
。