Template Default Arguments

Template default arguments

Note:

Foo me; without template arguments is legal as of C++17. See this answer: https://stackoverflow.com/a/50970942/539997.

Original answer applicable before C++17:

You have to do:

Foo<> me;

The template arguments must be present but you can leave them empty.

Think of it like a function foo with a single default argument. The expression foo won't call it, but foo() will. The argument syntax must still be there. This is consistent with that.

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

Member function of class with template arguments and default arguments outside class

Outside of your class definition, it will be unclear to a function what type Allocator is, so you have to redeclare it just like you redeclared T

template <class T, class Allocator>
void CustomContainer<T,Allocator>::push_back(T value)
{
// ...
}

(I'm assuming that DataType should be T)

Note that your declaration of push_back, in the class should match the definition:

template <typename T, typename Allocator = CustomAllocator<T> >
class CustomContainer
{
void push_back(T);
};

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.

Default template arguments for function templates

It makes sense to give default template arguments. For example you could create a sort function:

template<typename Iterator, 
typename Comp = std::less<
typename std::iterator_traits<Iterator>::value_type> >
void sort(Iterator beg, Iterator end, Comp c = Comp()) {
...
}

C++0x introduces them to C++. See this defect report by Bjarne Stroustrup: Default Template Arguments for Function Templates and what he says

The prohibition of default template arguments for function templates is a misbegotten remnant of the time where freestanding functions were treated as second class citizens and required all template arguments to be deduced from the function arguments rather than specified.

The restriction seriously cramps programming style by unnecessarily making freestanding functions different from member functions, thus making it harder to write STL-style code.

Why can't I have template and default arguments?

You certainly can; put the default argument on the declaration, not the definition.

Putting the default in the definition's argument list instead of the declaration's is an added extra that is not available for function templates:

[C++14: 8.3.6/4]: For non-template functions, default arguments can be added in later declarations of a function in the same scope. [..]

I don't really know why this restriction is in place.

Similar rule:

[C++14: 8.3.6/6]: Except for member functions of class templates, the default arguments in a member function definition that appears outside of the class definition are added to the set of default arguments provided by the member function declaration in the class definition [..]

How to specify a default argument for a template parameter pack?

There's already two excellent answers so far (including NathanOliver's comment). I think that having a couple of overloads that act as wrappers is really the simplest solution here, but just for completeness, let's provide your desired functionality in one function:

Often it's best to take as much of the template logic out of the parameter list as possible (separating inputs from logic):

template <std::size_t N, std::size_t... Indices>
void doSomething()
{
using Ints
= std::conditional_t<
/* if */ (sizeof...(Indices) > 0),
std::index_sequence<Indices...>,
/* else */
std::make_index_sequence<N>>;

// ...
};

demo

Template default argument loses its reference type

For foo<int>(a), ARG_T is being deduced from a, and is not taken from the default template argument. Since it's a by value function parameter, and a is an expression of type int, it's deduced as int.

In general, default template arguments are not used when template argument deduction can discover what the argument is.

But we can force the use of the default argument by introducing a non-deduced context for the function parameter. For instance:

template <class T, class ARG_T = T&>
T foo(std::enable_if_t<true, ARG_T> v1){
//...
}

Or the C++20 type_identity utility, such as the other answer demonstrates.



Related Topics



Leave a reply



Submit