推断类型是否可以存储在 boost::variant 中
Deduce if type can be stored in boost::variant
我使用boost::variant
已经有一段时间了,但仍有一些问题让我感到困惑。
以下代码未编译,因为我试图将 std::pair<int, int>
存储到 boost::variant
,它只能包含 int
、double
和 std::string
。我仍然需要函数 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
可能是解决方案的一部分,但我无法结束它。
The following code is not compiling, as I'm trying to store a std::pair<int, int>
to a boost::variant
, that can only contain int
, double
and std::string
. Still I need the function convert, but it should throw an exception in case I'm trying to store a type in the boost::variant
that it will not fit.
这实际上不是您应该想要的,您应该对自己的行为感到高兴。
如果您试图将类型存储在 boost::variant
中,但它不适合,这是您程序中的一个问题,编译器在编译时会很明显——编译器没有想法如何继续操作,实际上没有合理的代码可供它为此发出。它知道你要存储的类型,它知道你有什么样的变体,它可以看到没有转换。
当编译器拒绝代码并告诉您没有转换时,它会在了解问题后立即告诉您问题。
如果它只是在 运行 尝试转换时抛出异常,这意味着您要等到稍后的测试才能发现问题。这更烦人且代价更高——这意味着编译器知道或应该知道错误的转换问题,但决定掩盖它。
出于这个原因,通常在 C++ 中,程序员会尝试编写代码,使任何常见错误都表现为编译时错误而不是 运行 时错误。 boost::variant
就是怀着这个想法写的。
因此,我认为您应该重新审视问题的前提,并尝试解释您实际尝试做的事情。
这是我的方法,使用 SFINAE。这不是最好的解决方案,因为每次 add/remove 来自 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 */
因此,仅当上述条件之一为 true
时才采用模板 convert
,这将适用于 boost::variant
.
中的类型
我使用boost::variant
已经有一段时间了,但仍有一些问题让我感到困惑。
以下代码未编译,因为我试图将 std::pair<int, int>
存储到 boost::variant
,它只能包含 int
、double
和 std::string
。我仍然需要函数 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
可能是解决方案的一部分,但我无法结束它。
The following code is not compiling, as I'm trying to store a
std::pair<int, int>
to aboost::variant
, that can only containint
,double
andstd::string
. Still I need the function convert, but it should throw an exception in case I'm trying to store a type in theboost::variant
that it will not fit.
这实际上不是您应该想要的,您应该对自己的行为感到高兴。
如果您试图将类型存储在 boost::variant
中,但它不适合,这是您程序中的一个问题,编译器在编译时会很明显——编译器没有想法如何继续操作,实际上没有合理的代码可供它为此发出。它知道你要存储的类型,它知道你有什么样的变体,它可以看到没有转换。
当编译器拒绝代码并告诉您没有转换时,它会在了解问题后立即告诉您问题。
如果它只是在 运行 尝试转换时抛出异常,这意味着您要等到稍后的测试才能发现问题。这更烦人且代价更高——这意味着编译器知道或应该知道错误的转换问题,但决定掩盖它。
出于这个原因,通常在 C++ 中,程序员会尝试编写代码,使任何常见错误都表现为编译时错误而不是 运行 时错误。 boost::variant
就是怀着这个想法写的。
因此,我认为您应该重新审视问题的前提,并尝试解释您实际尝试做的事情。
这是我的方法,使用 SFINAE。这不是最好的解决方案,因为每次 add/remove 来自 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 */
因此,仅当上述条件之一为 true
时才采用模板 convert
,这将适用于 boost::variant
.