214

If I am allowed to do the following:

template <typename T = int>
class Foo{
};

Why am I not allowed to do the following in main?

Foo me;

But I must specify the following:

Foo<int> me;

C++11 introduced default template arguments and right now they are being elusive to my complete understanding.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user633658
  • 2,463
  • 2
  • 18
  • 16

6 Answers6

262

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.

Michael Hoffmann
  • 2,411
  • 2
  • 24
  • 42
Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • 6
    @Pubby I suppose it would create some unnecessary complications if `Foo` *might* be a template identifier or *might* be an explicit instantiation depending on whether there's a default argument. Better keep the explicit instantiation syntax. Think of it like a function `foo` with a single default parameter. You can't call it like `foo`, you call it with `foo()`. It makes sense to keep this consistent. – Joseph Mansfield Mar 12 '13 at 22:54
  • 3
    @sftrabbit but you can't call a function with no arguments like `foo` either; you can name a class with no arguments as `Foo` however. – Seth Carnegie Mar 12 '13 at 22:58
  • 1
    @aschepler I'm only guessing that they were trying to be consistent, not that they actually are. :D – Joseph Mansfield Mar 12 '13 at 22:59
  • @SethCarnegie But that's a class, this is a template. If you instantiate a template, you must give the template arguments (except the situation noted by @aschepler). I know, not the best of arguments. – Joseph Mansfield Mar 12 '13 at 23:00
  • 4
    @aschepler With a function, the template arguments can be deduced from the function arguments. With a class, it's not possible to decide, whether you meant a template class with default arguments or a non template class. – Olaf Dietsche Mar 12 '13 at 23:09
  • 25
    @OlafDietsche but you can't have a template class and a non-template class with the same name, so the compiler should be able to decide by just looking at what the name is. – Seth Carnegie Mar 12 '13 at 23:13
  • 7
    @Pubby The standard committee asked themselves the same, I guess. Now, with C++17, the `<>` is no more necessary in this case. Check out my answer for more details. – Paolo M Jun 21 '18 at 14:27
  • 1
    It stinks that I can't convert code that uses a Matrix class with floats, and decide later to change it to Matrix so double's can also be used w/o breaking old code. Std committee got this one wrong. – wcochran Dec 18 '18 at 21:39
111

With C++17, you can indeed.

This feature is called class template argument deduction and add more flexibility to the way you can declare variables of templated types.

So,

template <typename T = int>
class Foo{};

int main() {
    Foo f;
}

is now legal C++ code.

Paolo M
  • 12,403
  • 6
  • 52
  • 73
  • 6
    Strange. Just tried it in my C++17 project and it didn't work: "template placeholder type ‘const MyType’ must be followed by a simple declarator-id". I am using GCC 7.3.0. – Silicomancer Apr 16 '19 at 12:34
  • 1
    @Silicomancer It's hard to say without seeing your code and command line... Maybe are you dealing with pointers [like here](https://stackoverflow.com/questions/46085683/template-argument-deduction-for-class-templates-in-c17-am-i-doing-it-wrong)? – Paolo M Apr 16 '19 at 16:30
  • 1
    Clang doesnt accept it seems? http://coliru.stacked-crooked.com/a/c5d3c0f90ed263c2 – Borgleader Jun 20 '19 at 18:10
  • 1
    @Borgleader Apparently, Coliru is using clang 5.0. Judging by [this](https://en.cppreference.com/w/cpp/compiler_support), it should support C++17 template argument deduction, but evidently id doesn't. If you try your very same example in [wandbox](https://wandbox.org/permlink/4kW9NzRUq9pvUJJS) using clang 7.0, it works flawlessly. – Paolo M Jun 27 '19 at 07:54
  • 2
    @PaoloM Oh cool, glad to know its just a compiler version issue. Thanks for looking into this. – Borgleader Jun 27 '19 at 13:04
  • While the class template argument deduction as introduced by C++17 works well with GCC 8.X onwards it leads to a bug in GCC 7.X when combining default template data types and constant overloading (http://www.cs.technion.ac.il/users/yechiel/c++-faq/const-overloading.html). Consider the following example: https://wandbox.org/permlink/YoFIUEYNXZ80D6UN Even though one might expect the last instance "WhatAboutMe" to be a constant object it calls the non-constant implementation of "Method". As a consequence e.g. operators are able to change members of this seemingly constant object. – 2b-t Oct 28 '19 at 23:37
  • 5
    This should be top answer - the top answer is outdated. – drew.neely May 09 '20 at 20:08
  • 1
    In short: You need at least gcc 7.0+ (ideally 8.0+) or clang 7.0+. – LNJ Jul 04 '20 at 18:41
31

You are not allowed to do that but you can do this

typedef Foo<> Fooo;

and then do

Fooo me;
g24l
  • 3,055
  • 15
  • 28
22

You can use the following:

Foo<> me;

And have int be your template argument. The angular brackets are necessary and cannot be omitted.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • Makes sense and thank you but, as noted below, why do the type specifies have ot be present? – user633658 Mar 12 '13 at 22:57
  • @user633658: Did you mean "type specifier"? I'm not sure I understand – Andy Prowl Mar 12 '13 at 23:02
  • Anyway, concerning the reason behind the need for empty angular brackets, I can only make conjectures, and they're all about ruling out possible ambiguities with the usage of the template's name alone, but I have to confess that I do not know the exact reason – Andy Prowl Mar 12 '13 at 23:11
  • I strongly suspect the requirement for the <> is to enable the compiler's parser to determine that you are referring to a templated class called foo, rather than something else called foo. – Mac Nov 30 '16 at 21:40
1

Somewhat different case and rather later but where a template function is involved. gcc 11.2 can't seem to compile this:

template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
    Test t;
    foo<Test>(t);
}

but has no problem with

template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
    Test t;
    foo<Test<>>(t);
}

Of course

template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
    Test t;
    foo(t);
}

works - but sometimes you need to explicitly force the type. Is this a compiler bug?

Radrich
  • 61
  • 4
  • Note that this depends on compiler version - your third sample doesn't work in C++14 but works in C++17. This appears to be down to C++ language spec, not compiler error. Specifically, if you're going to *partially* specify a template (e.g. `foo(t)`), you *need* to provide <> for every defaulted template - however just putting `foo(t)` works fine. – Ethan McTague Mar 30 '22 at 16:33
  • The answer gives additional information, but it appears to be speculative or partially a question itself. – Ethan McTague Mar 30 '22 at 16:36
  • The actual usage that provoked this "questionable answer" requires the template argument. In that case it's not a partial specialization. I think that's actually the same case here - it is fully specialized. I believe there's another reason why this doesn't compile (but thanks for your comment). – Radrich Mar 30 '22 at 19:16
  • I threw in this queston: https://stackoverflow.com/questions/71683140/defaulted-template-in-template-function-requires-empty-angle-brackets – Radrich Mar 30 '22 at 19:34
  • If you have a new question, please ask it by clicking the [Ask Question](https://stackoverflow.com/questions/ask) button. Include a link to this question if it helps provide context. - [From Review](/review/late-answers/31414482) – Sneftel Mar 31 '22 at 23:18
0

As per the C++17 Standard, template arguments are necessary to be passed.

But if you still want a way around this, you can use using keyword like this

template <typename T>
class Foo{
};
using IFoo=Foo<int>

Or, you can also use preprocessor like this

template <typename T>
class Foo{
};

#define IFoo Foo<int>

Quick Reminder

Preprocessors are bad for debugging.

Yogesh Aggarwal
  • 1,071
  • 2
  • 12
  • 30