使用类模板需要指定模板参数时,如果默认的非类型模板参数值已经被指定,会出现“使用类模板需要模板参数”错误。

4

编译这个:

#include <iostream>
#include <memory>

template <auto val = 42>
struct A
{
    A()
    {
        std::cerr << val << "\n";
    }
};


int main(int argc, const char* argv[])
{
    std::shared_ptr<A> a_ptr {new A {}};

    return 0;
}

出现错误:使用类模板'A'需要模板参数。尽管我为非类型模板参数提供了默认值,希望编译器能够看到并使用它。我在这里错过了什么?

谢谢。


尝试使用 A<> 来实现该功能。 - Andrew Tomazos
是的,它与A<>一起很好用,但我认为有一些绕过A<>的方法。 - psb
你可以使用A() :D。开玩笑的,如果没有实例,你无法避免这个纯类型推断问题。这就是为什么 A a; 可以正常工作,但 std::shared_ptr<A<>> ptr; 需要更多信息的原因。 - Cedric
2个回答

7

这仍然是一个模板,仍然需要使用<>标签:

std::shared_ptr<A<>> a_ptr {new A<> {}};

想象一下,如果您有一个带有默认参数的函数:

int foo(int baz=42);

你认为你可以不带圆括号直接调用它吗?
int foobar=foo;

当然不行,这样是无法工作的。你仍需要使用括号:
int foobar=foo();

模板也是同样的道理。


2
哎呀,我用模板已经好多年了,从来没有在函数调用语法和带有默认参数的模板实例化之间建立起心理联系。这是一个很好的答案。 - Human-Compiler

1

A不是指一个类,而是指一个类模板。

你需要使用A<>来命名使用默认值的模板实例化:

std::shared_ptr<A<>> a_ptr {new A<> {}};
//              ^~~ here and    ^~~ here

如果您使用的是或更高版本,正如auto模板参数所暗示的那样,您可以从A构造中删除<>,因为这符合CTAD的要求,但在shared_ptr类型中仍然需要。
std::shared_ptr<A<>> a_ptr {new A {}};
//              ^~~ only here

注意: 只有在类型没有歧义的情况下才适用。如果构造函数符合CTAD,则会推导出与 A<> 可能不同的类型。

例如,如果定义了 A 如下:

template <typename T = int>
struct A
{
    A(){}
    A(T x){}
};

然后:

std::shared_ptr<A<>> a_ptr {new A {}};

会成功,但是

std::shared_ptr<A<>> a_ptr {new A {0.1}};

如果写成new A{0.1},则会失败,因为其推导出的是A<double>,但 A<> 指代的是 A<int>


看起来应该再加一个A<>, 就像这样std::shared_ptr<A<>> a_ptr {new A<> {}}; - psb
2
@Human-Compiler:我认为你需要在shared_ptr中使用A<>,而不是new。 - Cedric
哎呀,谢谢你指出来——我试图快速输入并且还是第二个答案。我已经添加了一些额外的注释来说明这一点。此外,A {}只适用于CTAD,但在更复杂的表达式中可能会产生与A<>不同的歧义。 - Human-Compiler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接