首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何正确地将boost::variant替换为std::variant?

如何正确地将boost::variant替换为std::variant?
EN

Stack Overflow用户
提问于 2019-07-09 15:42:12
回答 1查看 1.1K关注 0票数 7

使用boost:variant

代码语言:javascript
复制
#include <tuple>
#include <iostream>
#include <boost/variant.hpp>

template <size_t n, typename... T>
boost::variant<T...> _tuple_index(size_t i, const std::tuple<T...>& tpl) {
    if (i == n)
        return std::get<n>(tpl);
    else if (n == sizeof...(T) - 1)
        throw std::out_of_range("Out of Index");
    else
        return _tuple_index<(n < sizeof...(T)-1 ? n+1 : 0)>(i, tpl);
}
template <typename... T>
boost::variant<T...> tuple_index(size_t i, const std::tuple<T...>& tpl) {
    return _tuple_index<0>(i, tpl);
}

template <typename T>
auto tuple_len(T &tpl) {
    return std::tuple_size<T>::value;
}

int main()
{
    std::tuple<std::string, double, double, int> t("123", 4.5, 6.7, 8);
    for(int i = 0; i != tuple_len(t); ++i) {
        std::cout << tuple_index(i, t) << std::endl; // works with boost
    }
}

boost::variant替换为std::variant,为流std::variant添加了一个助手

代码语言:javascript
复制
#include <tuple>
#include <iostream>
#include <variant>

template <size_t n, typename... T>
std::variant<T...> _tuple_index(size_t i, const std::tuple<T...>& tpl) {
    if (i == n)
        return std::get<n>(tpl);
    else if (n == sizeof...(T) - 1)
        throw std::out_of_range("Out of Index");
    else
        return _tuple_index<(n < sizeof...(T)-1 ? n+1 : 0)>(i, tpl);
}
template <typename... T>
std::variant<T...> tuple_index(size_t i, const std::tuple<T...>& tpl) {
    return _tuple_index<0>(i, tpl);
}

template <typename T>
auto tuple_len(T &tpl) {
    return std::tuple_size<T>::value;
}

// added helper to stream std::variant
template <typename T0, typename ... Ts>
std::ostream & operator<< (std::ostream & s, std::variant<T0, Ts...> const & v) { 
    std::visit([&](auto && arg){ s << arg;}, v); 
    return s;
}

int main()
{
    std::tuple<std::string, double, double, int> t("123", 4.5, 6.7, 8);
    for(int i = 0; i != tuple_len(t); ++i) {
        std::cout << tuple_index(i, t) << std::endl; // doesn't work anymore
    }
}

编译仍然是错误的:

代码语言:javascript
复制
$ clang++ -v                                                                                                                                                                                                                                                            [17:37:47]
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

$ clang++ -std=c++17 isostd.cpp

isostd.cpp:8:16: error: no viable conversion from returned value of type 'const typename tuple_element<1UL, tuple<basic_string<char>, double, double, int> >::type' (aka 'const __type_pack_element<1UL, std::__1::basic_string<char>, double, double, int>') to function return
      type 'std::variant<basic_string<char>, double, double, int>'
        return std::get<n>(tpl);
               ^~~~~~~~~~~~~~~~
isostd.cpp:12:16: note: in instantiation of function template specialization '_tuple_index<1, std::__1::basic_string<char>, double, double, int>' requested here
        return _tuple_index<(n < sizeof...(T)-1 ? n+1 : 0)>(i, tpl);
               ^
isostd.cpp:16:12: note: in instantiation of function template specialization '_tuple_index<0, std::__1::basic_string<char>, double, double, int>' requested here
    return _tuple_index<0>(i, tpl);
           ^
isostd.cpp:35:22: note: in instantiation of function template specialization 'tuple_index<std::__1::basic_string<char>, double, double, int>' requested here
        std::cout << tuple_index(i, t) << std::endl; // doesn't work anymore
                     ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/variant:1142:3: note: candidate constructor not viable: no known conversion from 'const typename tuple_element<1UL, tuple<basic_string<char>, double, double, int> >::type'
      (aka 'const __type_pack_element<1UL, std::__1::basic_string<char>, double, double, int>') to 'const std::__1::variant<std::__1::basic_string<char>, double, double, int> &' for 1st argument
  variant(const variant&) = default;
  ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/variant:1143:3: note: candidate constructor not viable: no known conversion from 'const typename tuple_element<1UL, tuple<basic_string<char>, double, double, int> >::type'
      (aka 'const __type_pack_element<1UL, std::__1::basic_string<char>, double, double, int>') to 'std::__1::variant<std::__1::basic_string<char>, double, double, int> &&' for 1st argument
  variant(variant&&) = default;
  ^
/Library/Developer/CommandLineTools/usr/include/c++/v1/variant:1155:13: note: candidate template ignored: substitution failure [with _Arg = const double &, $1 = 0, $2 = 0, $3 = 0, _Tp = double]: no member named 'value' in
      'std::__1::__find_detail::__find_unambiguous_index_sfinae<double, std::__1::basic_string<char>, double, double, int>'
  constexpr variant(_Arg&& __arg) noexcept(
            ^
1 error generated.

如何正确地将boost:variant替换为std::variant?

我知道引用:std::变体和boost::变体有什么区别?

Boost.Variant包括recursive_variant,它允许变体包含自己。它们本质上是指向助推::变体的指针的特殊包装器,但它们被绑定到访问机制中。

如果我理解正确,就没有办法完成替换?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-07-09 15:56:35

由于您的变体中有重复类型,因此禁用了一些建设者

此过载仅参与过载解析,如果类型中恰好出现T.

您需要将构造函数与显式类型索引一起使用:

代码语言:javascript
复制
return std::variant<T...>(std::in_place_index<n>, std::get<n>(tpl));

最初的boost代码有未定义行为

在移除限定符后,指定为变量的模板参数的每种类型都必须是不同的。因此,例如,variant<int, int>variant<int, const int>都有未定义的行为。

标准的libary实现确实支持重复类型,因此防止您意外地构造一个复杂的变体。例如,应采取以下措施:

代码语言:javascript
复制
variant<std::string, double, double, int> t = 4.5;

对于boost,它是UB,任何一个double值都可能被初始化,或者它可能做一些完全不同的事情。标准库说明了这是一个编译器错误,因此您必须选择要初始化的double中的哪个。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56956221

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档