【问题标题】:Why can't this template argument be deduced?为什么不能推导出这个模板参数?
【发布时间】:2021-05-27 04:18:02
【问题描述】:

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())' 也不起作用。

【问题讨论】:

  • @Someprogrammerdude 仍然无法在 OnlineGDB 上运行,我会尝试获取链接:onlinegdb.com/2uWTCJUIO
  • template &lt;typename FooType = Foo&lt;&gt;()&gt; 工作 godbolt.org/z/PofM4Erx9
  • @JerryJeremiah 里面的括号是干什么的?我会理解&lt;typename FooType = Foo&lt;&gt;&gt;Foo&lt;&gt;()?显然它确实有效,但我不明白如何。
  • @JerryJeremiah 谢谢你让我走上正轨! :)
  • @Zebrafish Foo() 是一个不带参数并返回 Foo 的函数,而 int() 是一个不带参数并返回 int 的函数。两者都是类型 - 只是不是您正在寻找的类型。所以你可以使用 Foo 或 decltype(Foo()) 就像下面的答案建议的那样。

标签: c++ templates


【解决方案1】:

问题在于Foo 不是一个类型,它是一个类型的模板

这里需要指定一个实际的类型,需要模板尖括号Foo&lt;&gt;,也就是Foo&lt;double, 2, 3&gt;的类型:

typename FooType = Foo<>

【讨论】:

  • 感谢您的解释,这完全有道理,“Foo 不是一种类型,它是一种类型的模板”。顺便说一句,我不明白 Jerry Jeremiah 的解决方案,他也没有解释,在 ()> 'Foo()' 不是类型,这就像在做 typename IntType = int() ,这也很奇怪,即使 int() 不是类型。
  • @Zebrafish int() 是一种类型(不带参数的函数返回 int)。
  • int() 既是类型又是表达式。在这种情况下,类型选择en.cppreference.com/w/cpp/language/template_parameters
【解决方案2】:

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

typename FooType = decltype(Foo())

【讨论】:

  • 嗨。这就说得通了。我犯了使用 typename FooType = Foo() 的愚蠢错误,但 decltype 也不起作用onlinegdb.com/HxujYBmcc
  • @Zebrafish:它确实有效。你用的是哪个编译器??尝试更高版本
  • @Zebrafish gcc11 应该没问题 试过了
  • @nhatnq godbolt.org/z/v6h3x1593 上的代码(与之前评论中的 onlinegdb.com/HxujYBmcc 上的代码相同)有效,但我不知道为什么它得到的结果与你所做的不同。
  • @Zebrafish 这个错误来自编译器。无论如何,它已在更高版本中修复
【解决方案3】:

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

您可以将 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-09
    • 2018-03-23
    • 2017-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-28
    相关资源
    最近更新 更多