Using a class template that is the member of a class - c++

You can have a "shorthand" for a class template from a namespace by only giving the name of the template. However if the class template is in a class, I have to create an alias template and write out all the template parameters and arguments - which is bad for maintainability:
namespace mynamespace {
template<template<class> class T>
class MyClass;
}
using mynamespace::MyClass; // OK, straight and simple
class MyOuterClass {
public:
template<template<class> class T>
class MyInnerClass;
};
// using MyInnerClass = MyOuterClass::MyInnerClass; // error: invalid use of template-name 'MyOuterClass::MyInnerClass' without an argument list
// template<typename... TArgs> // error: type/value mismatch at argument 1 in template parameter list for 'template<template<class> class T> class MyOuterClass::MyInnerClass'
// using MyInnerClass = MyOuterClass::MyInnerClass<TArgs...>;
template<template<class> class T> // OK, but copying the template parameter list is bad, there should be some "auto" mechanism...
using MyInnerClass = MyOuterClass::MyInnerClass<T>;
int main(){}
Run code
Can I have a "shorthand" for such a template in a simpler way?

No. There is no such way. To using statements which are used (no pun intended) to make the definition visible are actually different versions of the same keyword. One is a using declaration, and another is an alias for typedef. They work differently and provide for different (though some times similarly looking) results.

If MyOuterClass::MyInnerClass<> only had type template parameters, you could use the following variadic alias template:
template<typename... TArgs>
using MyInnerClass = MyOuterClass::MyInnerClass<TArgs...>;
However, you still have to provide the parameter pack TArgs.
Assuming C++17, if MyOuterClass::MyInnerClass<> only had non-type template parameters you could use the following variadic alias template:
template<auto... Val>
using MyInnerClass = MyOuterClass::MyInnerClass<Val...>;

Related

Clang does not notice default template parameters

Background
According to the C++ standard, when forward-declaring a template type with default template parameters, each of them can appear in one declaration only. For example:
// GOOD example
template <class T = void>
class Example; // forward-declaration
template <class T>
class Example {}; // definition
// GOOD example
template <class T>
class Example; // forward-declaration
template <class T = void>
class Example {}; // definition
// BAD example
template <class T = void>
class Example; // forward-declaration
template <class T = void> // ERROR: template parameter redefines default argument
class Example {}; // definition
Problem
In my code I have a lot of forward declaration in different files, so it makes sense to put my default parameters in the definition:
// foo.hpp, bar.hpp, baz.hpp, etc.
template <class T>
class Example;
// example.hpp
template <class T = void>
class Example {};
and, as expected, it all works well everywhere... except clang! I narrowed the problem down to this:
In clang, if the class template has default parameters, but they are not declared in the first forward declaration of that class, and when declaring an instance of that class no angle brackets are specified, clang ignores the default parameter and raises an error "no viable constructor or deduction guide for deduction of template arguments of ...".
Example
// GOOD example
template <class T>
class Example;
template <class T = void>
class Example {};
int main() {
Example e; // error: no viable constructor or deduction guide for deduction of template arguments of 'Example'
}
Moving = void to the forward declaration fixes the issue, but is not viable for me since my forward-decls are in different files and I don't know which one will appear first. (Also super problematic since my defaults would be in some obscure file deep in the codebase)
Changing Example e; to Example<> e; fixes the issue, but is not viable for me since I'm a library dev and don't want all my users typing <> after my classes.
Adding a forward-declaration file example_fwd.hpp with one forward-declaration and including it instead of forward declaring every time fixes the issue, but I would like to avoid this if there is a better solution.
Question
Who is right in this case: clang or the other compilers? Is this a compiler bug? How can I circumvent this issue (apart from partial solutions I described above)?
I've found #10147 (and related stackoverflow questions), but it's about template template params and also is marked as fixed over a year ago.
Edit
This looks like a bug, and is now reported on LLVM bugtracker (#40488).
I don't know who's right but...
How can I circumvent this issue (apart from partial solutions I described above)?
What about adding the following deduction rule?
Example() -> Example<>;
The following code compile (C++17, obviously) with both g++ and clang++
template <class T>
class Example;
template <class T = void>
class Example {};
Example() -> Example<>;
int main() {
Example e;
}
Considering the following:
[temp.param]/12 - The set of default template-arguments available for use is obtained by merging the default arguments from all prior declarations of the template in the same way default function arguments are [ Example:
template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;
is equivalent to
template<class T1 = int, class T2 = int> class A;
— end example ]
The default arguments available for
template <class T>
class Example;
template <class T = void>
class Example {};
will be the defaults arguments in the definition of Example. The two declarations above will be equivalent to have a single declaration as
template <class T = void>
class Example {};
which will effectively allow doing Example e.
The original code should be accepted. As a workaround and already suggested in max66's answer, you can provide a deduction guide that uses the default argument
Example() -> Example<>;
The standard does not make distinction whether a default template argument is defined in the definition or a declaration of a template.
Because Clang accepts the code when the default argument appears in the declaration, but not in the definition, at least one of this two behaviors is wrong. Considering [over.match.class.deduct]/1.1.1:
The template parameters are the template parameters of C followed by the template parameters (including default template arguments) of the constructor, if any.
, I am tempted to say that Clang should use the default template argument.
I think that you could avoid this bug by following a common practice:
If a declaration must be forwarded, create a dedicated header file for this forward declaration.
Define default arguments in this forward declaration file
Also include this file in the header file that provides the definition of the template.
As an example see iosfwd: libstdc++/iosfwd

How to set std::vector as default parameter of template?

I would like to make a template class which has two template arguments. First - N is a class of variable default set as int and second container is a container from stl and default is set as std::vector.
#include <iostream>
#include <vector>
template <class N=int,
template <class T=N, class Allocator=std::allocator<N>>
class container=std::vector>
class foo{
container<N> cont;
};
int main()
{
foo f;
}
When I created object f of above class without template arguments then the compiler wrote a folowing error:
In function 'int main()':
15:9: error: missing template arguments before 'f'
I would like foo to be equivalent to the foo<int, std::vector> declaration.
Where is an issue is my class definition?
With C++14 or before, you need to write foo<> in order to instantiate the template.
From C++17 on, it actually just works as you wrote it because of Class Template Argument Deduction. You might consider updating your C++ language version with -std=c++17 if your compiler supports it.

Why can't template template parameters be introduced with "typename"? [duplicate]

Template template typename?
When using template template syntax as in template <template <typename> class T>, it is required to use the keyword class, as using typename gives an error along the lines of:
error: template template parameter requires 'class' after the parameter list
Everywhere else the keywords typename and class are interchangeable in the basic case of declaring a template parameter.
You could argue that the requirement when using template template is a hint that you are expected to pass a class type, but this is not always the case (especially not after C++11 introduced templated type aliases).
template <template <typename> class T> // 'class' keyword required.
struct Foo {
using type = T<int>;
};
template <typename T>
using type = T (*)();
using func_ptr_t = Foo<type>::type;
What is the reasoning behind this?
Is there any specific reason as to why typename is not allowed in template template declarations?
Does the C++ standard say anything about this?
Short answer: because the Standard says so.
Longer answer: prior to Standardization, C++ templates required the class keyword for all template parameters. However, to stress the fact that templates could also be of non-class (i.e. builtin) type, an alternative keyword typename was introduced. However, in C++98, template-template parameters could only be of class-type, and this was the reason that the typename keyword was not added in that context.
Enter C++11 and its new feature template aliases, that now also introduced non-class templates, and hence non-class template-template parameters:
template<typename T> struct A {};
template<typename T> using B = int;
template<template<typename> class X> struct C;
C<A> ca; // ok
C<B> cb; // ok, not a class template
template<template<typename> typename X> struct D; // error, cannot use typename here
The above example was taken from the current C++1z proposal N4051 titled Allow typename in a template template parameter, and proposes to allow precisely that.
Clang 3.5 SVN now supports this with the -std=c++1z flag.
I'm looking for the rational behind this restriction [...]
Before C++11 was introduced, the only templates you could pass to a template template parameter were class templates.
That's why the use of the keyword class was enforced.
Additionally, the keyword typename implies that the template parameter is a substitution for an arbitrary type and not a template, so using typename in that context would just blur the line between the names of types and (class) templates.
That's comprehensible.
Nowadays, such arguments can be the names of class templates or alias templates, and since those aren't even remotely connected, the enforcement of the keyword class is more or less obsolete. The proposal N4051 opts to change this with C++1Z.

Why does not a template template parameter allow 'typename' after the parameter list

Template template typename?
When using template template syntax as in template <template <typename> class T>, it is required to use the keyword class, as using typename gives an error along the lines of:
error: template template parameter requires 'class' after the parameter list
Everywhere else the keywords typename and class are interchangeable in the basic case of declaring a template parameter.
You could argue that the requirement when using template template is a hint that you are expected to pass a class type, but this is not always the case (especially not after C++11 introduced templated type aliases).
template <template <typename> class T> // 'class' keyword required.
struct Foo {
using type = T<int>;
};
template <typename T>
using type = T (*)();
using func_ptr_t = Foo<type>::type;
What is the reasoning behind this?
Is there any specific reason as to why typename is not allowed in template template declarations?
Does the C++ standard say anything about this?
Short answer: because the Standard says so.
Longer answer: prior to Standardization, C++ templates required the class keyword for all template parameters. However, to stress the fact that templates could also be of non-class (i.e. builtin) type, an alternative keyword typename was introduced. However, in C++98, template-template parameters could only be of class-type, and this was the reason that the typename keyword was not added in that context.
Enter C++11 and its new feature template aliases, that now also introduced non-class templates, and hence non-class template-template parameters:
template<typename T> struct A {};
template<typename T> using B = int;
template<template<typename> class X> struct C;
C<A> ca; // ok
C<B> cb; // ok, not a class template
template<template<typename> typename X> struct D; // error, cannot use typename here
The above example was taken from the current C++1z proposal N4051 titled Allow typename in a template template parameter, and proposes to allow precisely that.
Clang 3.5 SVN now supports this with the -std=c++1z flag.
I'm looking for the rational behind this restriction [...]
Before C++11 was introduced, the only templates you could pass to a template template parameter were class templates.
That's why the use of the keyword class was enforced.
Additionally, the keyword typename implies that the template parameter is a substitution for an arbitrary type and not a template, so using typename in that context would just blur the line between the names of types and (class) templates.
That's comprehensible.
Nowadays, such arguments can be the names of class templates or alias templates, and since those aren't even remotely connected, the enforcement of the keyword class is more or less obsolete. The proposal N4051 opts to change this with C++1Z.

what does template<> (without any class T in the <>) mean?

I'm reading some source code in stl_construct.h,
In most cases it has sth in the <>
and i see some lines with only "template<> ...".
what's this?
This would mean that what follows is a template specialization.
Guess, I completely misread the Q and answered something that was not being asked.
So here I answer the Q being asked:
It is an Explicit Specialization with an empty template argument list.
When you instantiate a template with a given set of template arguments the compiler generates a new definition based on those template arguments. But there is a facility to override this behavior of definition generation. Instead of compiler generating the definition We can specify the definition the compiler should use for a given set of template arguments. This is called explicit specialization.
The template<> prefix indicates that the following template declaration takes no template parameters.
Explicit specialization can be applied to:
Function or class template
Member function of a class template
Static data member of a class template
Member class of a class template
Member function template of a class template &
Member class template of a class template
It's a template specialization where all template parameters are fully specified, and there happens to be no parameters left in the <>.
For example:
template<class A, class B> // base template
struct Something
{
// do something here
};
template<class A> // specialize for B = int
struct Something<A, int>
{
// do something different here
};
template<> // specialize both parameters
struct Something<double, int>
{
// do something here too
};