Reputation: 13886
The parameters for Foo have default values, therefore in main() I can do Foo(); to create a Foo and it'll have the default template arguments. However I cannot use in a template argument:
template <typename T = double, int a =2, int b = 3>
struct Foo {};
//cannot deduce template arguments for ‘Foo’ from ()
template <typename FooType = Foo()> // <-- Error
struct TemplatedStructTakingAFooType
{
};
int main()
{
Foo(); // Foo type is deduced to be default values, ie.,
//Foo<double, 2, 3>;
decltype(Foo()); // Compiler knows the type
}
In my Visual Studio compiler it highlights the area in red indicating an error, but compiles. On onlineGDB under C++17 is fails to compile with the above error. Is this allowed? Is there any reason it shouldn't be?
Edit: I realised how stupid using is as Foo() isn't a type, but neither '= Foo' nor '= decltype(Foo())' work either.
Upvotes: 2
Views: 209
Reputation: 6131
Something will have to change because you're mixing ideas.
You can pass Foo as either
Here's an example of each:
template <typename T = double, int a =2, int b = 3>
struct Foo {};
// As a type. The caller has secided what the template arguments that Foo
// will have, or by allowing them to default, has chosen the defaults.
template <typename FooType = decltype(Foo{})>
struct A
{
};
// Here FooType is passed as a template. Inside B, you'd need to
// provide it template parameters to instantiate it.
template <template <typename T, int, int> typename Foo2 = Foo>
struct B
{
using F = Foo2<float, 3, 4>;
};
// As a user-defined non-type template parameter
// This only works in C++20, since it's a new feature
template <Foo f>
struct C
{
};
// And finally, CTAD to with deduced arguments for Foo as a user-defined
// non-type tempalte parameter, with friendly constructor syntax. (For the
// caller, not for the reader of this monstrosity).
// The deduction guide allows passing an instance of Foo<T, a, b> to the
// constructor and allowing it to match types for T, a, b for the struct.
template <typename T, int a, int b, Foo<T, a, b> f>
struct D
{
D(Foo<T, a, b>) { }
};
template <typename T, int a, int b> D(Foo<T, a, b>) -> D<T, a, b, Foo<T, a, b>{}>;
int main()
{
A a; // default
A<Foo<float, 5, 9>> a2; // give types to Foo given to A
B<Foo> b; // Pass Foo to b as a template-template param
C<Foo{}> c; // Pass instance of Foo with default args
Foo<short, 99, 0> customFoo;
D d(customFoo); // Pass instance to constructor(!) to
// set template args even when Foo is not default.
}
See it live: https://godbolt.org/z/8MGcn6zjj
Upvotes: 0
Reputation: 1193
Foo()
is not a type so need decltype
:
typename FooType = decltype(Foo())
Upvotes: 3
Reputation: 409146
The problem is that Foo
isn't a type, it's a template of a type.
You need to specify an actual type here, which needs the template angle-brackets, Foo<>
which is the type Foo<double, 2, 3>
:
typename FooType = Foo<>
Upvotes: 5