can template alias be used for partial specialization? - c++

Given a template alias
template<unsigned U>
using uint_ = integral_constant<unsigned,U>;
The partial specialization of
template<class T,class P>
struct size{};
as
template <class T,unsigned U>
struct size<T,uint_<U>>{};
generates a warning astemplate parameter can not be deduced for clang 3.1 while no warning is generated with gcc 4.7
So, is it malformed code?

The code is perfectly fine in C++11. The Clang's warning can be ignored.

Another guy said that this is a Clang bug. You can work it around if you change the using declaration like this
template<unsigned T, unsigned U = T>
using uint_ = integral_constant<unsigned,U>;
As an educated guess, apparently Clang does not correctly update the identity of the template parameter that appears in the type-id. So it thinks in your example that the resulting type uint_<U> refers to the first parameter of the partial specialization (because within uint_ that is the case, but not in the point of use). Alternatively you can exchange the order at the point of use
template <unsigned U,class T>
struct size<T,uint_<U>>{};

Related

Try to remember template template argument passed into template for later re-use [duplicate]

I try to create template alias which cannot be distinguished from original.
So, I create traits to check when 2 templates (not types) are equal:
template <template <class...> class C1,
template <class...> class C2>
struct is_same_template : std::false_type {};
template <template <class...> class C1>
struct is_same_template<C1, C1> : std::true_type {};
Now test it:
// Expected alias
template <typename ... Ts> using V_Ts = std::vector<Ts...>; // Variadic
// Fallback alias
template <typename T, typename A> using V = std::vector<T, A>; // Exact count
static_assert(!is_same_template<std::vector, V_Ts>::value); // Alias rejected by gcc/clang
static_assert( is_same_template<std::vector, V>::value); // Alias accepted only for gcc
Demo
Is it possible to create "true" alias?
which compiler is right?
I try to create template alias which cannot be distinguished from original.
I don't think this is currently possible. There are (unfortunately) no template aliases, there are only alias templates. And an alias template is always a template of its own [temp.alias]/1. A specialization of an alias template is equivalent to the type you get by substituting the template arguments into the alias template, but the alias template itself is not an alias for another template [temp.alias]/2. I would consider GCC letting your second static_assert pass a bug in GCC…
As pointed out by #HolyBlackCat in the comment above, there is a related question and answer which points to numerous related CWG issues. One issue in particular (CWG 1286) would seem to suggest that there is desire to allow an alias template to itself be equivalent to the template it refers to under certain circumstances. However, it does not seem that the proposed resolution has been adopted due to concerns raised later. The relevant wording in the current standard draft ([temp.alias] and [temp.type]) appears to be unchanged from C++11…

Compiler discrepancy with simple meta function

When I try to use the following meta function to retrieve the first type of a tuple, the code can be compiled with GCC but not with Clang. I have two questions regarding the little snippet.
Is this legal C++ code? And why? Or why not?
Is there a workaround (or correct alternative) which works for both compilers?
#include <tuple>
template<typename>
struct first_type;
template<template<typename, typename...> typename T, typename T1, typename... Ts>
struct first_type<T<T1, Ts...>>
{ using type = T1; };
template<typename T>
using first_type_t = typename first_type<T>::type;
using tuple_type1 = first_type_t<std::tuple<int, int, double>>;
Live example
As requested, the error message generated by Clang:
<source>:12:1: error: implicit instantiation of undefined template
'first_type<std::tuple<int, int, double>>'
using first_type_t = typename first_type<T>::type;
^
<source>:14:21: note: in instantiation of template type alias
'first_type_t' requested here
using tuple_type1 = first_type_t<std::tuple<int, int, double>>;
^
<source>:4:8: note: template is declared here
struct first_type;
^
In conclusion:
As answered by IWonderWhatThisAPIDoes; to circumvent the compiler discrepancy completely, simply drop the requirement of the templated template argument to have at least a single type.
As pointed out by Nathan Oliver; if you need the first type of a tuple (or really any type given an index), simply use the std::tuple_element meta function instead.
As pointed out by HolyBlackCat; it seems the ruling that Clang enforces regarding templated template arguments, is stricter than technically required by the standard. This behavior can be disabled by passing the -frelaxed-template-template-args compiler flag.
Temporarily changing your struct declaration to (thus getting rid of the incomplete type):
template<typename>
struct first_type {};
Changes the error you get to:
no type named 'type' in 'first_type<std::tuple<int, int, double>>'
This gives us valuable information: the compiler chose the generic version of the template, implying that Clang does not consider tuple to be a valid template<typename,typename...>class to instantiate first_type with (which is true - template<typename,typename...>class takes one or more parameters, while a tuple can also be empty). As pointed out in the comments, this does not matter to the standard itself, but Clang rejects it on purpose.
A tuple is a template<typename...>class, so...
template<template<typename...> typename T, typename T1, typename... Ts>
struct first_type<T<T1, Ts...>> {
using type = T1;
};

Partial template specialization with non-type parameters: GCC vs MSVS

Consider this simple template specialization:
template<typename T, size_t I>
struct S {};
template<typename T>
struct S<T, std::tuple_size<T>::value> {};
GCC does not compile it, as it uses template parameter T in the template argument std::tuple_size<T>::value:
error: template argument 'std::tuple_size<_Tp>::value'
involves template parameter(s)
Now let's replace T with typename std::remove_reference<T>::type in tuple_size template argument:
// Using primary structure template from previous example.
template<typename T>
struct S<T, std::tuple_size<typename std::remove_reference<T>::type>::value> {};
This code still uses template parameter in template argument, but GCC compiles it without any errors or warnings. Why?
Now if we try to compile the second example using MSVS with /std:c++latest flag, it stops with error C2755:
non-type parameter of a partial specialization must be a simple
identifier
What is this strange restriction? I want to stop compile-time recursion when I becomes equal to tuple size.
So who of them is wrong: MSVS or GCC?
Note that MSVS reports the error even without any template instantiations, while GCC works fine with all of these instances:
S<std::tuple<int, float>, 9> s1;
S<std::tuple<int, float>, 2> s2;
S<int, 42> s3;
I use MSVS Community 2015 Update 3 with it's default compiler and GCC 6.2.1.
Tried Clang 3.8.0. It does not compile both snippets with an error similar to GCC's message:
error: non-type template argument depends on a template parameter of
the partial specialization
The specific section of the standard dealing with the viability of a partial class template specialization has been changed lots of times over the last few years. The original restrictionin [temp.class.spec.match] read:
A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier.
Your code clearly runs afoul of that, std::tuple_size<T>::value is not an identifier.
It then changed, after cwg issue 1315, to read:
Each template-parameter shall appear at least once in the template-id outside a non-deduced context.
But we're okay there - T is used in a non-deduced context as the first template parameter. And after template auto, it now reads:
If the template arguments of a partial specialization cannot be deduced because of the structure of its
template-parameter-list and the template-id, the program is ill-formed.
But we're okay there too. It can be deduced, you have the right "structure" - your specialization is using a non-type template parameter in the same location as the primary, and they should match fine.
I think following the resolution of 1315 (which I think is post-C++14), the code should be well-formed, but both gcc and clang reject it. An unfortunate fix would be to use two type parameters instead:
template <class T, class I>
struct S;
template<typename T>
struct S<T, typename std::tuple_size<T>::type> {};
template <size_t I>
using size_ = std::integral_constant<size_t, I>;
int main() {
S<std::tuple<int>, size_<1>> s;
}
Both gcc and clang accept that one.

Proper way to use SFINAE struct defintions

For educative reasons, I was playing around with the SFINAE behavior of C++ and building my own version of std::enable_if in a rather simplified form. I noticed different behavior when using slightly different implementation details though:
Implementation as incomplete type:
template <bool C, typename> struct enable_if; // incomplete type
template <typename T> struct enable_if<true, T> { typedef T type; };
Implementation as empty type:
template <bool C, typename> struct enable_if {}; // empty type
template <typename T> struct enable_if<true, T> { typedef T type; };
On g++ (4.8.1 and 4.3.2) both versions compile and behave the same way. MSVC 2008 seems to only accept the definition as an empty type.
Are both definitions valid C++, and should they be equivalent in behavior?
From the standard, § 14.8.2:
Type deduction may fail for the following reasons:
[...]
Attempting to use a type in a nested-name-specifier of a qualified-id
when that type does not contain the specified member, or the specified
member is not a type where a type is required [...]
Both cases are handled in the same sentence, so from my understanding it really should not make a difference - both implementations should be equivalent.

aliased templates in nested classes

I am trying to get a template alias for T2<B> starting from an instance of C.
template<typename A>
struct T1
{
template<typename B>
struct T2{};
};
template<typename A>
class C
{
T1<A> t;
};
template<typename A>
using U1=decltype(C<A>::t);
template<typename A, typename B>
using U2=typename U1<A>::T2<B>;
I get a compiler failure with gcc 4.8:
gg.cc:18:28: error: expected ‘;’ before ‘<’ token
using U2=typename U1<A>::T2<B>;
I have used the typename keyword in every sensible location, but can't get the U2 definition to compile.
What is the correct syntax here? It would be even better if I could get a definition of U2 without resorting to U1.
You need to use the template disambiguator to tell the compiler to parse T2 as the name of a template (and the subsequent < and > as delimiters of the corresponding template arguments):
template<typename A, typename B>
using U2=typename U1<A>::template T2<B>;
// ^^^^^^^^
Here is a compiling live example.
Here you can find some more information on when you should use the template disambiguator (and the typename disambiguator as well, although you seem to be aware of that one).
When the compiler compiles the following:
template<typename A, typename B>
using U2=typename U1<A>::T2<B>;
After it reads the nested name specifier U1<A>::, it doesn't know which specialization of U1 it is in, because A is unknown. Each U1 specializaiton could be totally different, and depend on what A is. So it has no idea what kind of name T1 is. In particular it doesn't know whether it is a template name or not. (For example U1<int>::T1 could be totally different to what U1<char>::T1 is.)
For this reason you need to explicitly tell the compiler that T1 is going to be a template name by using the template keyword before T1.