Clang fails to compile parameter pack expansion using template metaprogramming

Janoma

I have a boost::variant of several ranges. In this context, a range is just a std::pair<It, It>, where It is an iterator. I use this to store ranges of iterators satisfying certain properties.

Since I don't know the iterator types, I use a little template meta-programming to obtain the first_type of the std::pair, since I need a second boost::variant containing a single iterator (corresponding to some active element of that type).

The following code is simplified to help with the question, but consider that I have an unknown number of ranges in my RangeVariant (which means I can't create it manually, as I can do for this particular case).

#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>;
};

The above program compiles correctly with gcc, but fails with clang. The error I get is the following:

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_;
       ^

So, it seems clang is attempting to obtain the first_type of boost::detail::variant::void_, but somehow gcc recognizes it and ignores it. Something similar happens if I obtain the type for the first element using the <tuple> header:

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

The error after this change is different, but again related to clang trying to apply the operation to 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...>;

I'm using boost 1.57.0, gcc 4.8.3 and clang 3.6.0, always using -std=c++11 with -Wall -Werror -Wextra flags. Using other versions of either of these is not an option :-(

Any help would be appreciated. I don't even know whether this is a bug in clang or boost, or even in gcc, if my usage is incorrect. Thanks in advance for your help.

Janoma

Although both Chris' and Felipe's contributions answer my question partially (thanks guys!), here is an update that actually compiles with the Boost and clang versions I mentioned.

First, update the specialization of FirstTypeVariant so that it obtains the type from another structure instead of directly obtaining T::first_type:

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

Then, specialize the ObtainFirstType struct so that it returns the iterator type for std::pair<T, T> (remember that in my use case, T is an iterator).

template <typename T>
struct ObtainFirstType
{
    using type = T;
};

template <typename T>
struct ObtainFirstType<std::pair<T, T>>
{
    using type = T;
};

Now, this will compile and work, but there's a caveat. The number of elements of the variant with clang will always be 20, so any algorithm depending on that might change its behavior. We can count them like this:

template <typename... Ts>
struct VariantSize
{
    static constexpr std::size_t size = 0;
};

template <typename... Ts>
struct VariantSize<boost::variant<Ts...>>
{
    static constexpr std::size_t size = sizeof...(Ts);
};

In my example, I created a variant with 3 elements, which I then counted:

int main()
{
    using ContainerA = std::vector<int>;
    using ContainerB = std::vector<double>;
    using ContainerC = std::vector<bool>;
    using RangeA = std::pair<ContainerA::iterator, ContainerA::iterator>;
    using RangeB = std::pair<ContainerB::iterator, ContainerB::iterator>;
    using RangeC = std::pair<ContainerC::iterator, ContainerC::iterator>;

    using RangeVariant = boost::variant<RangeA, RangeB, RangeC>;
    using IteratorVariant = FirstTypeVariant<RangeVariant, boost::variant>;

    std::cout << "RangeVariant size    : " << std::to_string(VariantSize<RangeVariant>::size) << std::endl;
    std::cout << "IteratorVariant size : " << std::to_string(VariantSize<IteratorVariant>::size) << std::endl;
};

The output with GCC is

RangeVariant size    : 3
IteratorVariant size : 3

while the output with CLANG is the following:

RangeVariant size    : 20
IteratorVariant size : 20

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

when template parameter of a template template-parameter is pack expansion, gcc fails, clang succeeds

From Dev

Template Parameter Pack Fails on Clang but not VS 2015

From Dev

Template Parameter Pack Fails on Clang but not VS 2015

From Dev

Parameter pack expansion fails

From Dev

a variadic template as a template parameter without pack expansion

From Dev

Template deduction fails with argument after parameter pack

From Dev

C++: parameter pack expansion inside lambda fails

From Dev

Variadic template pack expansion

From Dev

Parameter pack expansion questions

From Dev

Using a runtime parameter (variable) in C++ metaprogramming at compile-time

From Java

Clang fails to expand parameter pack in std::function instantiation

From Dev

Clang vs GCC - Variadic template parameter pack followed by parameter with default value works in GCC 4.8 but not Clang 3.5

From Dev

Compile time array from C++ template parameter pack

From Dev

Variadic template indexed pack expansion

From Dev

Simple parameter pack expansion: expected ';'

From Dev

Parameter pack expansion for static variables

From Dev

parameter pack expansion not working in lambda

From Dev

Template Metaprogramming for concatenation of compile-time sequences

From Dev

Bitswap function using template metaprogramming

From Dev

Clang fails to compile template function in a template class specialization, which has *distinct return type* from the template declaration

From Dev

Clang fails to compile template function in a template class specialization, which has *distinct return type* from the template declaration

From Dev

Empty parameter pack expansion different to manual empty parameter pack

From Dev

Is the order for variadic template pack expansion defined in the standard?

From Dev

Variadic template pack expansion argument id

From Java

Problem with order of evaluation in parameter pack expansion

From Dev

Add all parameters with parameter pack expansion

From Dev

What is the syntax for parameter pack expansion with alignas?

From Dev

Templates. Parameter pack expansion - remap types

From Dev

C++ using a template parameter pack to invoke multiple templated functions

Related Related

  1. 1

    when template parameter of a template template-parameter is pack expansion, gcc fails, clang succeeds

  2. 2

    Template Parameter Pack Fails on Clang but not VS 2015

  3. 3

    Template Parameter Pack Fails on Clang but not VS 2015

  4. 4

    Parameter pack expansion fails

  5. 5

    a variadic template as a template parameter without pack expansion

  6. 6

    Template deduction fails with argument after parameter pack

  7. 7

    C++: parameter pack expansion inside lambda fails

  8. 8

    Variadic template pack expansion

  9. 9

    Parameter pack expansion questions

  10. 10

    Using a runtime parameter (variable) in C++ metaprogramming at compile-time

  11. 11

    Clang fails to expand parameter pack in std::function instantiation

  12. 12

    Clang vs GCC - Variadic template parameter pack followed by parameter with default value works in GCC 4.8 but not Clang 3.5

  13. 13

    Compile time array from C++ template parameter pack

  14. 14

    Variadic template indexed pack expansion

  15. 15

    Simple parameter pack expansion: expected ';'

  16. 16

    Parameter pack expansion for static variables

  17. 17

    parameter pack expansion not working in lambda

  18. 18

    Template Metaprogramming for concatenation of compile-time sequences

  19. 19

    Bitswap function using template metaprogramming

  20. 20

    Clang fails to compile template function in a template class specialization, which has *distinct return type* from the template declaration

  21. 21

    Clang fails to compile template function in a template class specialization, which has *distinct return type* from the template declaration

  22. 22

    Empty parameter pack expansion different to manual empty parameter pack

  23. 23

    Is the order for variadic template pack expansion defined in the standard?

  24. 24

    Variadic template pack expansion argument id

  25. 25

    Problem with order of evaluation in parameter pack expansion

  26. 26

    Add all parameters with parameter pack expansion

  27. 27

    What is the syntax for parameter pack expansion with alignas?

  28. 28

    Templates. Parameter pack expansion - remap types

  29. 29

    C++ using a template parameter pack to invoke multiple templated functions

HotTag

Archive