Template template parameter and default values
As far I know, your code is correct starting from C++17, wrong before.
This according P0522R0, that is part of new standard, where I see an example that is very, very similar to your code (see "overview"):
template <template <typename> class> void FD();
template <typename, typename = int> struct SD { /* ... */ };
FD<SD>(); // OK; error before this paper (CWG 150)
According the compiler support tables in ccpreference, g++ support P0522R0 from version 7, clang++ from version 4. So both compiler should support your code.
But looking the table in this page, the support for llvm (clang) 5 is defined "partial" and, according a note,
(12): Despite being the the resolution to a Defect Report, this feature is disabled by default in all language versions, and can be enabled explicitly with the flag -frelaxed-template-template-args in Clang 4 onwards. The change to the standard lacks a corresponding change for template partial ordering, resulting in ambiguity errors for reasonable and previously-valid code. This issue is expected to be rectified soon.
So, at your risk, you can try with the flag -frelaxed-template-template-args
.
Default template parameter cannot be used inside another template parameter?
This:
DefaultType obj;
uses CTAD (class template argument deduction) which is available since C++17 and only in certain contexts:
- any declaration that specifies initialization of a variable and variable template
- new-expressions
- function-style cast expressions
- the type of a non-type template parameter:
To instantiate DefaultType
with the default argument in other contexts you still need to write DefaultType<>
.
I suppose the reason to have CTAD only in certain contexts is that those are the contexts where you always want an instantiation, but never the template.
Template default argument
The problem of your code is that for Y
you ask a type template parameter and you want to use a template template parameter.
template <typename A, typename B> class X {};
// type template template
//........VVVVVVVVVV VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
template <typename T=template <typename, typename> class X> class Y {};
int main()
{
Y<> y;
return 0;
}
If you want to use X
as default, T
must be be a template template, so
template <typename, typename>
class X
{};
template <template <typename, typename> class T = X>
class Y
{};
int main ()
{
Y<> y;
}
Or also using variadics to improve flexibility
template <template <typename...> class T = X>
class Y
{};
Default values in templates with template arguments ( C++ )
Perhaps you'd prefer this:
#include <vector>
#include <list>
using namespace std;
template <class Container>
class ForExamplePurposes {
typedef typename Container::value_type T;
Container items;
public:
};
int main()
{
ForExamplePurposes< list<int> > a;
ForExamplePurposes< vector<float> > b;
}
This uses "static duck typing". It is also a bit more flexible as it doesn't force the Container type to support STL's Allocator concept.
Perhaps using the type traits idiom can give you a way out:
#include <vector>
#include <list>
using namespace std;
struct MyFunkyContainer
{
typedef int funky_type;
// ... rest of custom container declaration
};
// General case assumes STL-compatible container
template <class Container>
struct ValueTypeOf
{
typedef typename Container::value_type type;
};
// Specialization for MyFunkyContainer
template <>
struct ValueTypeOf<MyFunkyContainer>
{
typedef MyFunkyContainer::funky_type type;
};
template <class Container>
class ForExamplePurposes {
typedef typename ValueTypeOf<Container>::type T;
Container items;
public:
};
int main()
{
ForExamplePurposes< list<int> > a;
ForExamplePurposes< vector<float> > b;
ForExamplePurposes< MyFunkyContainer > c;
}
Someone who wants to use ForExamplePurposes
with a non-STL-compliant container would need to specialize the ValueTypeOf
traits class.
C++: Default values for template arguments other than the last ones?
In general, both in templates and functions or methods, C++ lets you use default for (and thereby omit) only trailing parameters -- no way out.
I recommend a template or macro to shorten AnObnoxiouslyLongSequenceOfCharacters<MyKeyType>
to Foo<MyKeyType>
-- not perfect, but better than nothing.
Why c++ allows default template argument that can never be used?
But it can be used. Here's an example.
auto* foo_ptr = &foo<>; // The default template argument is used.
A function call expression is not the only context where a function template's arguments need to be figured out.
Can C++ deduce argument type from default value?
The type of a template parameter in a function can't be deduced from a default argument. As shown in the example on cppreference.com:
Type template parameter cannot be deduced from the type of a function
default argument:template<typename T> void f(T = 5, T = 7);
void g()
{
f(1); // OK: calls f<int>(1, 7)
f(); // error: cannot deduce T
f<int>(); // OK: calls f<int>(5, 7)
}
However, you can specify a default argument for the template parameter:
template<typename A, typename B = int>
void func(int i1, int i2, A a, B b = 123){
...
}
Default template arguments for the C++11 'using' type alias
Introduction
Having default values for template-parameters in a alias-template is legal, but you cannot leave out <
, and >
, when you are later using said alias.
template<class T = float>
using val = value<T, 2>;
val<> v; // legal, decltype(v) => value<float, 2>
val<int> w; // legal, decltype(w) => value<int, 2>
What does the Standard say? (n3337)
14.5.7p1
Alias templates[temp.alias]
A template-declaration in which the declaration is an alias-declaration (Clause 7) declares the identifier to be a alias-template. An alias template is a name for a family of types. The name of the alias template is a template-name.
The above states that the name introduced by a template-alias is a template-name, and a template-name must be followed by a template-argument-list.
14.2p1
Names of template specialization[temp.names]
simple-template-id:
template-name < template-argument-list_opt >
template-name:
identifier
Note: Notice how the two <>
are not optional when referring to a simple-template-id, and that a template-name by itself is merely an identifier, not a type.
Related Topics
Class Template for Numeric Types
Unresolved External Symbol "Public: Virtual Struct Qmetaobject Const * _Thiscall Parent
How to Assign Multiple Values into a Struct at Once
C Preprocessor MACro Specialisation Based on an Argument
Performance Penalty for Working with Interfaces in C++
How Can It Be Useful to Overload the "Function Call" Operator
How Much Overhead Is There When Creating a Thread
What's the Usual Way of Controlling Frame Rate
Memory-Efficient C++ Strings (Interning, Ropes, Copy-On-Write, etc)
Implementing the Visitor Pattern Using C++ Templates
When to Use 'Asio_Handler_Invoke'
What Are Potential Dangers When Using Boost::Shared_Ptr
How to Validate That a String Is a Valid Ipv4 Address in C++
What's the Best Way to Check If a File Exists in C++? (Cross Platform)
Serialize and Send a Data Structure Using Boost
Macro/Keyword Which Can Be Used to Print Out Method Name