c++ - Clang 无法使用模板元编程编译参数包扩展

标签 c++ clang metaprogramming template-meta-programming boost-variant

我有一个 boost::variant几个范围。在这种情况下,范围 只是一个 std::pair<It, It> , 其中It是一个迭代器。我用它来存储满足某些属性的迭代器范围。

因为我不知道迭代器类型,所以我使用一点模板元编程来获得 first_typestd::pair ,因为我需要第二个 boost::variant包含单个迭代器(对应于该类型的某些事件元素)。

以下代码经过简化以帮助解决问题,但考虑到我的 RangeVariant 中的范围数量未知。 (这意味着我无法手动创建它,但对于这种特殊情况我可以这样做)。

#include <utility>
#include <vector>

#include <boost/variant.hpp>

template <class A, template <typename...> class B>
struct FirstTypeVariantImpl;

template <template <typename...> class A, typename... Pair, template <typename...> class B>
struct FirstTypeVariantImpl<A<Pair...>, B> /*! specialization */
{
    using type = B<typename Pair::first_type...>;
};

template <class A, template <typename...> class B>
using FirstTypeVariant = typename FirstTypeVariantImpl<A, B>::type;

int main()
{
    using Container = std::vector<int>;
    using Range = std::pair<Container::iterator, Container::iterator>;
    using RangeVariant = boost::variant<Range>;
    using IteratorVariant = FirstTypeVariant<RangeVariant, boost::variant>;
};

上面的程序用 gcc 编译正确,但是用 clang 编译失败。我得到的错误如下:

program.cpp:12:29: error: incomplete type 'boost::detail::variant::void_' named in nested name specifier
using type = B<typename Pair::first_type...>;
                        ^~~~~~
program.cpp:16:1: note: in instantiation of template class 'FirstTypeVariantImpl<boost::variant<std::pair<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > >, boost::detail::variant::void_, ..., boost::detail::variant::void_>, variant>' requested here
using FirstTypeVariant = typename FirstTypeVariantImpl<A, B>::type;
^
program.cpp:23:29: note: in instantiation of template type alias 'FirstTypeVariant' requested here
using IteratorVariant = FirstTypeVariant<RangeVariant, boost::variant>;
                        ^
../../../include/boost/variant/variant_fwd.hpp:193:8: note: forward declaration of 'boost::detail::variant::void_'
struct void_;
       ^

所以,clang 似乎正在尝试获取 first_typeboost::detail::variant::void_ ,但 gcc 不知何故识别并忽略了它。如果我使用 <tuple> 获取第一个元素的类型,则会发生类似的情况。 header :

using type = B<typename std::tuple_element<0, Pair>::type...>;

此更改后的错误是不同的,但再次与 clang 尝试将操作应用于 boost::detail::variant::void_ 有关:

program.cpp:13:34: error: implicit instantiation of undefined template 'std::tuple_element<0, boost::detail::variant::void_>'
using type = B<typename std::tuple_element<0, Pair>::type...>;

我正在使用 boost 1.57.0、gcc 4.8.3 和 clang 3.6.0,始终使用 -std=c++11-Wall -Werror -Wextra旗帜。使用其中任何一个的其他版本都不是一种选择:-(

如有任何帮助,我们将不胜感激。如果我的用法不正确,我什至不知道这是否是 clang 或 boost 中的错误,甚至是 gcc 中的错误。预先感谢您的帮助。

最佳答案

我们同意 void_boost::variant 的一部分的预可变模板解决方法(每个实例化都是 boost::variant<MandatoryType, ⟪boost::detail::variant::void_ ⨉ 𝖫𝖨𝖲𝖳_𝖲𝖨𝖹𝖤 ⟫> )。

现在,问题是使用 metashell我发现至少存在一个版本的 boost::variant 使用此解决方法。

环顾四周,发现有一个bug recently fixed关于 boost 库如何无法正确识别 clang 的可变参数模板功能。

回答您的问题:gcc 编译是因为 boost 库识别可变参数模板的可用性,但缺少 clang 的。这导致 void_无法在您的元编程纠结中实例化为 struct已声明,但未定义。

关于c++ - Clang 无法使用模板元编程编译参数包扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36094280/

相关文章:

c++ - 使用 Boost::Spirit 从中缀到前缀的 n 元 bool 语法转换?

C++ 析构函数运行两次

c++ - 使用元编程的私有(private)成员存在性测试,GCC vs clang,哪个是对的?

linux - 从内核树中编译 eBPF C 代码时出错

c++ - 如何创建抽象类直到派生实例化

javascript - 延迟加载外部 Javascript 文件

c++ - 这个模板魔法如何确定数组参数大小?

c++ - 从文件中读取未知长度的 int 数组

c++ - 变量没有产生正确的数据

ruby - 是否有可能缩小 ruby 常量查找