为什么不能推导出这个模板参数?

时间:2021-05-27 04:18:02

标签: c++ templates

Foo 的参数有默认值,因此在 main() 中我可以做 Foo();创建一个 Foo ,它将具有默认的模板参数。但是我不能在模板参数中使用:

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
}

在我的 Visual Studio 编译器中,它以红色突出显示区域,指示错误,但可以编译。在 C++17 下的 onlineGDB 上编译失败并出现上述错误。这是允许的吗?有什么理由不应该吗?

编辑:我意识到使用是多么愚蠢,因为 Foo() 不是一种类型,但 '= Foo' 和 '= decltype(Foo())' 也不起作用。

3 个答案:

答案 0 :(得分:5)

问题在于 Foo 不是类型,而是类型的模板

您需要在此处指定一个实际类型,它需要模板尖括号,Foo<> 是类型 Foo<double, 2, 3>

typename FooType = Foo<>

答案 1 :(得分:3)

Foo() 不是一个类型所以需要 decltype:

typename FooType = decltype(Foo())

答案 2 :(得分:0)

有些东西必须改变,因为你在混合想法。

您可以将 Foo 作为其中之一传递

  1. 一个类型参数,
  2. 模板参数
  3. 用户定义的非类型模板参数(C++20 中的新增功能)

以下是每个示例:

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.
}

现场观看:https://godbolt.org/z/8MGcn6zjj