C++ 为什么可以';这个模板参数不能推导吗?

C++ 为什么可以';这个模板参数不能推导吗?,c++,templates,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()> // <--

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
}
模板
结构Foo{};
//无法从()推断“Foo”的模板参数

template/问题在于
Foo
不是一种类型,而是一种类型的模板

您需要在此处指定一个实际类型,该类型需要模板尖括号,
Foo
,即类型
Foo

typename FooType=Foo
Foo()
不是类型,因此需要
decltype

typename FooType = decltype(Foo())

有些事情必须改变,因为你在混合想法

你可以通过Foo作为

  • 类型参数
  • 模板参数
  • 用户定义的非类型模板参数(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.
    }
    
    模板
    结构Foo{};
    //作为一种类型。调用者已隔离了Foo所使用的模板参数
    //将具有,或通过允许它们默认,已选择默认值。
    模板
    结构A
    {
    };
    //这里FooType作为模板传递。在B里面,你需要
    //提供it模板参数以对其进行实例化。
    模板
    结构B
    {
    使用F=Foo2;
    };
    //作为用户定义的非类型模板参数
    //这只适用于C++20,因为它是一个新特性
    模板
    结构C
    {
    };
    //最后,CTAD使用用户定义的Foo的推断参数
    //非类型tempalte参数,具有友好的构造函数语法。(对于
    //呼叫者,而不是这个怪物的读者)。
    //《扣减指南》允许将Foo实例传递给
    //构造函数,并允许它为结构匹配T、a、b的类型。
    模板
    结构D
    {
    D(Foo){}
    };
    模板D(Foo)->D;
    int main()
    {
    A;//默认值
    A a2;//给Foo类型给A
    B;//将Foo作为模板参数传递给B
    C;//使用默认参数传递Foo的实例
    Foo customFoo;
    D D(customFoo);//将实例传递给构造函数(!)以
    //即使Foo不是默认值,也要设置模板参数。
    }
    

    现场观看:

    @Someprogrammerdude仍然不能在OnlineGDB上工作,我将尝试获取链接:
    template
    works@JerryJeremiah这里面的括号在做什么?我会理解的,但是
    Foo()
    ?很明显,它确实有效,但我不明白它是如何起作用的。@JerryJeremiah谢谢你让我走上正轨的!:)@Zebrafish Foo()是一个不带参数并返回Foo的函数,int()是一个不带参数并返回int的函数。这两种函数都是类型,只是不是您要查找的类型。因此,您可以使用Foo或decltype(Foo()),如下面的答案所示。这是有道理的。我犯了一个愚蠢的错误,使用了typename FooType=Foo(),但是decltype也不起作用@Zebrafish:它确实起作用。您正在使用哪个编译器??试试更高的version@Zebrafishgcc11应该没问题tried@nhatnq位于的代码(与先前注释中位于onlinegdb.com/HxujYBmcc的代码相同)可以工作,但我不知道为什么它得到的结果与您的不同。@Zebrafish此错误来自编译器。无论如何,它在后来的版本中被修正了,因为它解释了“Foo不是一个类型,它是一个类型的模板”,这是完全有道理的。顺便说一句,Jerry Jeremiah的解决方案我不明白,他也没有解释,在'Foo()'中不是一种类型,这就像做typename IntType=int(),这也很奇怪,即使int()不是一种类型。@Zebrafish
    int()
    是一种类型(函数没有参数返回
    int
    ).int()既是类型又是表达式。在这种情况下,选择类型
    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.
    }