ChatGPT解决这个技术问题 Extra ChatGPT

Template default arguments

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.


M
Michael Hoffmann

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.


@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.
@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.
@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.
@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.
@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.
P
Paolo M

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.


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 It's hard to say without seeing your code and command line... Maybe are you dealing with pointers like here?
Clang doesnt accept it seems? coliru.stacked-crooked.com/a/c5d3c0f90ed263c2
@PaoloM Oh cool, glad to know its just a compiler version issue. Thanks for looking into this.
This should be top answer - the top answer is outdated.
g
g24l

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

typedef Foo<> Fooo;

and then do

Fooo me;

is there any difference in this with a default type and: typedef Foo<float> Fooo;, without a default type?
The C++11-ish way would be to say using Fooo = Foo<>;
A
Andy Prowl

You can use the following:

Foo<> me;

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


Makes sense and thank you but, as noted below, why do the type specifies have ot be present?
@user633658: Did you mean "type specifier"? I'm not sure I understand
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
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.
R
Radrich

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?


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<Test>(t)), you need to provide <> for every defaulted template - however just putting foo(t) works fine.
The answer gives additional information, but it appears to be speculative or partially a question itself.
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).
I threw in this queston: stackoverflow.com/questions/71683140/…
If you have a new question, please ask it by clicking the Ask Question button. Include a link to this question if it helps provide context. - From Review
Y
Yogesh Aggarwal

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.


This is plain worse than using IFoo=Foo<int>. Macro's ignore namespaces