Clang fails to compile parameter pack expansion using template metaprogramming - c++

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.

We agree on that void_ is part of boost::variant's pre-variadic template workaround (every instantiation is boost::variant<MandatoryType, ⟪boost::detail::variant::void_ ⨉ 𝖫𝖨𝖲𝖳_𝖲𝖨𝖹𝖤 ⟫>).
Now, the thing is that using metashell I found out there exists at least one version of boost::variant that does not use this workaround.
Looking around, I found that there was a bug recently fixed about how boost libs do not recognize clang's variadic template capability correctly.
To answer your question: gcc compiles because boost libs recognize variadic template availability, while missing clang's. This results in void_ failing to be instantiate in your meta-programming tangle as this struct has been declared, but not defined.

The reason this doesn't work is that boost::variant isn't implemented the way you think it is.
boost::variant like all of boost is compatible with C++03, before the time when there were variadic templates.
As a result, boost::variant has to work around the lack of that language feature, by imposing a maximum number of variants and using only C++03 template features.
The way they do this is, the template has 20 template arguments, and they all have a default value of boost::variant::detail::void_.
Your variadic capture is catching those extra parameters, just the same way that if you tried to capture all the parameters to std::vector you would get your type, also an allocator, etc., even if you didn't explicitly specify an allocator.
The work arounds I can think of off-hand are,
1) Don't use boost::variant, use a C++11 variant based on variadic templates. There are many implementations floating around.
2) Use boost variant, but also create a type-trait that permits you recover the original parameter pack from a typelist. You would have to make sure that every time you instantiate it, you also create an entry in the type trait, but you can use a macro to make sure that happens.
3) There may be a way to make boost::variant use an implementation based on variadic templates? But I'm not sure of this, I would have to review the docs. If there is then it means there is some preprocessor define you can use to force this.
Edit: The macro is this actually:
http://www.boost.org/doc/libs/1_60_0/doc/html/BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES.html
So in recent versions of boost, you have to request explicitly not to have the variadic implementation, unless you are on C++03 presumably?
You might want to explicitly check if something in one of your headers is defining this for some reason.

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

Related

Something like std::integral_constant but with auto template argument in std C++20 library?

Starting from C++20 one can use auto template argument to implement integral constant:
Try it online!
template <auto Value>
struct integral_constant2
: std::integral_constant<decltype(Value), Value> {};
which can be used instead of more verbose variant std::integral_constant that has two template arguments.
Sure its easier to write f(std::integral_constant2<123>{}); instead of more verbose f(std::integral_constant<int, 123>{});. More than that you may not know type in advance if you have complex compile-time expression.
My question is whether there exists in C++20 std library anything like integral_constant2 mentioned above, not to reinvent wheel? Or at least some std constexpr function std::make_integral_constant(123) that deduces std::integral_constant's template params?
No, I am not aware of such replacement.
I believe it would be difficult to defend such proposal, given how easy it is to write your own. On the other hand the only reason might be that nobody proposed it yet.
Mainly as a curiosity, and expanding on a comment, you can take this one step further via:
#include <type_traits>
template <auto Value, template<typename A, A> typename C>
using automized = C< decltype(Value),Value>;
template <auto Value>
using integral_constant = automized<Value,std::integral_constant>;
int main() {
struct S {};
integral_constant<true> c0{};
integral_constant<10> c1{};
integral_constant<S{}> c2{};
}
automized would allow to forward an auto parameter to any template taking typename T, T value. However, it is rather limited because it only works for templates taking exactly those parameters, while getting the general case right is rather painful when type and non-type parameters can be mixed.
You can see all new feature in C++20 here : https://en.cppreference.com/w/cpp/20
and I don't see anything related to integral_constant (and I don't see anything in the type_traits page either)

Create type, by reusing template template parameter

I work with template template parameters and want to construct new types based on template template parameters defined at another location. This sometimes works, but I think I miss something fundamentally, conceptually.
In the below minimal (I hope not too much distorted) example I expect the types of Example<GerericTemplate> and MakeAnotherX<Example<GenericTemplate>>::type to be identical, but they aren't always.
struct Something {};
template <template <typename> typename TemplateParameter>
struct Example {
template <typename T>
using InputTemplate = TemplateParameter<T>;
using FullType = TemplateParameter<Something>;
private:
FullType fData;
};
template <typename T>
struct GenericTemplate {};
// this works with (recent) GCC, but the static_assert below fails with clang
template <typename ExistingType,
template <typename> typename _InputTemplate
= ExistingType::template InputTemplate>
struct MakeAnother1 {
using type = Example<_InputTemplate>;
};
// this compiles, but static_assert below fails for both (recent) gcc and clang
template <typename ExistingType>
struct MakeAnother2 {
template <typename T> using _InputTemplate
= typename ExistingTemplate::template InputTemplate<T>;
using type = Example<_InputTemplate>;
};
#include <type_traits>
int main() {
using type1 = Example<GenericTemplate>;
static_assert(std::is_same<type1, MakeAnother1<type1>::type >::value, "this is not the same");
static_assert(std::is_same<type1, MakeAnother2<type1>::type >::value, "this is not the same");
return 0;
}
this example in godbolt
So far I am using gcc and clang (-std=c++17) for testing (and production), but in general I just wish to have standard compliant code. I really would like to be able to to reuse template template parameters in different context and classes as described in the minimal example above.
What is the correct way to achieve this in a robust manner? Also: is the fact that MakeAnother1 works with GCC a feature or a bug of GCC (and vice versa for clang)?
The "real code" is significantly more complex, so in particular I want those "Make" helper structs to work on new types.
Update
An earlier conceptually identical version of this question was asked about 6 years ago see old post. The news is that today this work on gcc version 5 and beyond but still no other compiler seems to support it. Unfortunately the discussion on CWG seems to have stalled on this point and could benefit from a reminder?
At this stage: after this update, if you prefer we can of course close this report here now. Thanks for all help!

Extracting types from boost:hana::set with partial specialization fails

I'm using the following template to declare a set of types:
template<class ...T>
using DependencySet = boost::hana::set<boost::hana::type<T>...>;
I would like to be able to extract those types back from the set and put in another container. I tried using a "classic" approach:
template<class ...T>
struct ExtractTypes;
template<class ...Dependencies>
struct ExtractTypes<DependencySet<Dependencies...>>
{
using type = SomeOtherType<Dependencies...>;
};
Alas, the compiler disagrees:
error: class template partial specialization contains a template
parameter that cannot be deduced; this partial specialization will
never be used [-Wunusable-partial-specialization]
struct ExtractTypes< DependencySet< Dependencies...>>
Is there a way to extract the types back from such set?
With regard to the compiler error, I think it is incorrect and you are probably using an older version of Clang or GCC.
Even with an up to date compiler your code is incorrect because it is making assumptions about the template parameters of hana::set which are documented as implementation defined since set is meant to be an unordered associative container.
Consider using the "types as values" approach which allows more expressive code, and it is what Boost.Hana is meant to facilitate.
For making a set, use hana::make_set, and to get the values back out you can use hana::unpack which calls a variadic function object with its contained values (in no specific order).
Here is an example:
#include <boost/hana.hpp>
#include <type_traits>
namespace hana = boost::hana;
template <typename ...T>
struct DependencySet { };
int main()
{
auto deps = hana::make_set(
hana::type<char>{}
, hana::type<int>{}
, hana::type<long>{}
);
auto dep_types = hana::unpack(deps, hana::template_<DependencySet>);
static_assert(
hana::typeid_(dep_types) == hana::type<DependencySet<char, int, long>>{}
, ""
);
}
As an aside, if you just want to put template parameters from one template into another, take a look at Boost.Mp11's mp_apply

Should the following code compile according to C++ standard?

#include <type_traits>
template <typename T>
struct C;
template<typename T1, typename T2>
using first = T1;
template <typename T>
struct C<first<T, std::enable_if_t<std::is_same<T, int>::value>>>
{
};
int main ()
{
}
Results of compilation by different compilers:
MSVC:
error C2753: 'C': partial specialization cannot match argument list for primary template
gcc-4.9:
error: partial specialization 'C' does not specialize any template arguments
clang all versions:
error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list
gcc-5+:
successfully compiles
And additionaly I want to point out that trivial specialization like:
template<typename T>
struct C<T>
{
};
successfully fails to be compiled by gcc. So it seems like it figures out that specialization in my original example is non-trivial. So my question is - is pattern like this explicitly forbidden by C++ standard or not?
The crucial paragraph is [temp.class.spec]/(8.2), which requires the partial specialization to be more specialized than the primary template. What Clang actually complains about is the argument list being identical to the primary template's: this has been removed from [temp.class.spec]/(8.3) by issue 2033 (which stated that the requirement was redundant) fairly recently, so hasn't been implemented in Clang yet. However, it apparently has been implemented in GCC, given that it accepts your snippet; it even compiles the following, perhaps for the same reason it compiles your code (it also only works from version 5 onwards):
template <typename T>
void f( C<T> ) {}
template <typename T>
void f( C<first<T, std::enable_if_t<std::is_same<T, int>::value>>> ) {}
I.e. it acknowledges that the declarations are distinct, so must have implemented some resolution of issue 1980. It does not find that the second overload is more specialized (see the Wandbox link), however, which is inconsistent, because it should've diagnosed your code according to the aforementioned constraint in (8.2).
Arguably, the current wording makes your example's partial ordering work as desired†: [temp.deduct.type]/1 mentions that in deduction from types,
Template arguments can be deduced in several different contexts, but in each case a type that is specified in terms of template parameters (call it P) is compared with an actual type (call it A), and an attempt is made to find template argument values […] that will make P, after substitution of the deduced values (call it the deduced A), compatible with A.
Now via [temp.alias]/3, this would mean that during the partial ordering step in which the partial specialization's function template is the parameter template, the substitution into is_same yields false (since common library implementations just use a partial specialization that must fail), and enable_if fails.‡ But this semantics is not satisfying in the general case, because we could construct a condition that generally succeeds, so a unique synthesized type meets it, and deduction succeeds both ways.
Presumably, the simplest and most robust solution is to ignore discarded arguments during partial ordering (making your example ill-formed). One can also orientate oneself towards implementations' behaviors in this case (analogous to issue 1157):
template <typename...> struct C {};
template <typename T>
void f( C<T, int> ) = delete;
template <typename T>
void f( C<T, std::enable_if_t<sizeof(T) == sizeof(int), int>> ) {}
int main() {f<int>({});}
Both Clang and GCC diagnose this as calling the deleted function, i.e. agree that the first overload is more specialized than the other. The critical property of #2 seems to be that the second template argument is dependent yet T appears solely in non-deduced contexts (if we change int to T in #1, nothing changes). So we could use the existence of discarded (and dependent?) template arguments as tie-breakers: this way we don't have to reason about the nature of synthesized values, which is the status quo, and also get reasonable behavior in your case, which would be well-formed.
† #T.C. mentioned that the templates generated through [temp.class.order] would currently be interpreted as one multiply declared entity—again, see issue 1980. That's not directly relevant to the standardese in this case, because the wording never mentions that these function templates are declared, let alone in the same program; it just specifies them and then falls back to the procedure for function templates.
‡ It isn't entirely clear with what depth implementations are required to perform this analysis. Issue 1157 demonstrates what level of detail is required to "correctly" determine whether a template's domain is a proper subset of the other's. It's neither practical nor reasonable to implement partial ordering to be this sophisticated. However, the footnoted section just goes to show that this topic isn't necessarily underspecified, but defective.
I think you could simplify your code - this has nothing to do with type_traits. You'll get the same results with following one:
template <typename T>
struct C;
template<typename T>
using first = T;
template <typename T>
struct C<first<T>> // OK only in 5.1
{
};
int main ()
{
}
Check in online compiler (compiles under 5.1 but not with 5.2 or 4.9 so it's probably a bug) - https://godbolt.org/g/iVCbdm
I think that int GCC 5 they moved around template functionality and it's even possible to create two specializations of the same type. It will compile until you try to use it.
template <typename T>
struct C;
template<typename T1, typename T2>
using first = T1;
template<typename T1, typename T2>
using second = T2;
template <typename T>
struct C<first<T, T>> // OK on 5.1+
{
};
template <typename T>
struct C<second<T, T>> // OK on 5.1+
{
};
int main ()
{
C<first<int, int>> dummy; // error: ambiguous template instantiation for 'struct C<int>'
}
https://godbolt.org/g/6oNGDP
It might be somehow related to added support for C++14 variable templates. https://isocpp.org/files/papers/N3651.pdf

Partial specialization of existing metafunction using mpl

Maybe I'm not all there today, but I'm wondering how to get this to work.
I'd like to partially specialize range_mutable_iterator and range_const_iterator from the boost library but only for specific types that I'd rather avoid mentioning explicitly, instead only letting the partial specialization be chosen if the enable_if test criteria pass.
I'm currently using MSVC 2008 and am receiving the following error:
ArrayType: template parameter not used or deducible in partial specialization on type
range_mutable_iterator<
typename enable_if<
mpl::and_<
mpl::has_key<some_type_map, typename remove_const<T>::type>,
mpl::not_<is_const<T> >
>,
ArrayType
>::type
>
Using STLFilt, notice the odd reference to T instead of ArrayType, I'm guessing STLFilt is saying it can't figure out that T == ArrayType..? Here's what I have right now:
namespace boost {
template<class ArrayType>
struct range_mutable_iterator<
typename enable_if<
mpl::and_<
mpl::has_key<some_type_map, typename remove_const<ArrayType>::type>,
mpl::not_<is_const<ArrayType> >
>,/*and_*/
ArrayType
>::type/*enable_if*/
>
{
typedef MyArrayIterator<
typename mpl::at<some_other_type_map,
typename mpl::at<yet_another_type_map,ArrayType>::type
>::type/*at*/
>/*MyArrayIterator*/ type;
};
}
Getting range_begin/range_end working isn't currently an issue, the goal is to have a line work that looks like this:
ThirdPartyArrayClass blah;
MyArrayAdapter<ThirdPartyArrayClass>::iterator iter = boost::begin(blah);
Edit: After having tried a different approach which I've edited out of this answer, I came to accept that partial specialization in this case just isn't possible, so I've used a different approach which involves full specialization and heavy use of Boost.Preprocessor.
In order to partially specialize a template the compiler must match the actual template arguments to the existing specializations, with the aim to select the best match. This is just not possible if the template argument in the specialization is used just as the (template) parameter to a dependent type. So, the compiler complains, and rightly so. The only thing you can do is to somehow specialize on your concrete ThirdPartyArrayClass type.