Default Values in Templates with Template Arguments ( C++ )

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



Leave a reply



Submit