aliased templates in nested classes - c++

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.

Related

Is clang right to complain about an out of line definition of a templated constructor using a concept?

Here is a struct with a templated constructor that is defined out of line:
template <typename T>
struct Foo {
template <typename F>
Foo(F f);
};
template <typename T>
template <typename F>
Foo<T>::Foo(F f) {}
Clang is happy with this under -std=c++20. If I add a requires clause to the templated constructor, it is still happy. But if the requires clause mentions the struct, it is not happy:
#include <concepts>
template <typename T>
struct Foo {
template <typename F>
requires (!std::same_as<Foo<T>, int>)
Foo(F f);
};
template <typename T>
template <typename F>
requires (!std::same_as<Foo<T>, int>)
Foo<T>::Foo(F f) {}
<source>:13:9: error: out-of-line definition of 'Foo<T>' does not match any declaration in 'Foo<T>'
Foo<T>::Foo(F f) {}
^~~
GCC does accept this.
Is clang right to reject it? And if so, what part of the standard says so?
If you're interested why I have a requires clause that references the type being constructed, it's to disambiguate the constructor from the move constructor so that the next requires clause in a larger requires expression won't be evaluated when F is the same as Foo . Otherwise it recursively depends upon itself. The real code is more complicated, and accepts a forwarding reference to F.
I think this could be related to the compiler not being able to deduce what T is. When using a requires clause inside a struct, the compiler needs to be able to instantiate the class template in order to check the requirements specified in the requires clause. This means that all template parameters used within the requires clause must be in scope and the compiler must be able to deduce their types.
If the class template is not fully defined yet, the compiler will not be able to instantiate it, and the code will not be able to compile. Just to be clear, I do not know with certainty, as I have barely used this feature.
As I sort of expected, this seems to be a known clang bug: https://github.com/llvm/llvm-project/issues/49620

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

Issue using template alias nested in object passed to template

I having a problem trying to get template to work with an alias nested in one of its arguments. It works if I make an alias in the template itself and use that as an argument to another template. I would like to use it without doing this so that it can be passed down through inheritance to another template.
I think my problem has something to do with the compiler not knowing what the template arguments are and says the template argument is invalid, but I don't know if there is a way to correct this without using the extra alias.
template< template<typename>class T >
struct TemplateWrapper {
template<typename U>
using type = T<U>;
};
template<typename T>
struct TemplateTester{
template<typename U>
using type = typename T::template type<U>; //This works fine
TemplateWrapper<type> test; //This works fine
TemplateWrapper< typename T::template type > test2; //error: template argument 1 is invalid
};
I'm using MinGW with GCC 4.7.1.
Any help would be appreciated.

c++ inherit from specialized template class

template<typename T1, typename T2, typename T3>
class A: public A<T1, T2, void> {
public:
T1 a;
T2 b;
T3 c;
void set() { a = aa; } // Cannot find variable `aa' here!
};
template<typename T1, typename T2>
class A<T1, T2, void> {
public:
T1 aa;
T2 bb;
};
As above, I have a template class A, and its partial specialized form A'. So is it possible for A to inherit from A'? According to g++, it seems OK. However, when I tried to access members in A', g++ started to complain: Fail to find that symbol. Anybody knows why?
As far as I remember you have to pull in aa to derived class with 'using'. Add the following (I do not remember exact syntax so forgive me any compilation issues) to your generic template:
using A<T1, T2, void>::aa;
EDIT: As Mehrdad noted this->aa should also work.
The name look up rules with C++ templates may seem a bit non-intuitive. When the compiler first parses the template definition, it resolves all names, which are not template-argument dependent. When it comes to template instantiation, it will resolve the rest.
If you take a look at the definition of class A only, there is no obvious dependence of the symbol aa on type arguments T1, T2 or T3. So the compiler tries to resolve the name, but it cannot, since that name is undefined in that environment.
So, to convince the compiler to do what you wanted, you have to use of the tricks below:
The easiest is probably this->aa. Since this has a template-argument dependent superclass, its members can only be looked up at template instantiation time, so everything is fine.
Qualify the member with the superclass, i.e. use A<T1, T2, void>::aa. This makes the dependency really obvious. You may also use the using directive, so that so do not have to type this every time.

can template alias be used for partial specialization?

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