一个lvalue引用的非类型模板参数可否被推断?

12

我有下面的代码,但是它无法正常运行:

struct foo {};
foo foo1 = {};

template <foo& F>
class FooClass {};

template <foo& F>
void foobar(FooClass<F> arg) {
}

int main() {
    FooClass<foo1> f;
    foobar(f);
}

错误原因是:

main.cpp:14:5: 错误: 没有符合调用'foobar'的函数

注: 候选模板被忽略: 替换失败: 推断出的非类型模板参数与其对应的模板参数类型不同 ('foo' vs 'foo &')

是否有可能推断出左值引用模板参数?如果可能,应该如何实现?


3
由于该参数是全局变量,因此该变量的“地址”是一个常量表达式。或者更确切地说,它具有固定的符号名称,可以用于实例化模板。同样,静态存储期变量的引用也可以用作模板参数。 - dyp
2
这可能是[temp.deduct.type]p17,但在这种情况下似乎过于严格:foo1作为表达式的(可观察)类型是foo,因此与模板参数F的类型foo&不完全匹配。这可能是标准中的缺陷。 - dyp
3
就我所知,我的 type_name 函数(https://dev59.com/qXVD5IYBdhLWcg3wHnwX#20170989)在 clang 和 gcc 上都将 f 的类型报告为 FooClass<foo1>。这代表了根据此处规定编写的独立版本的 __cxa_demangle:http://mentorembedded.github.io/cxx-abi/abi.html#mangling - Howard Hinnant
3
VS-2015 报告 f 的类型是 class FooClass<&struct foo foo1>。并且,它成功地编译了这个示例。 - Howard Hinnant
@101010 请查看[tem.arg.nontype]/1。该措辞是指参数必须是“常量表达式[...],但如果模板参数是引用,则可以省略&”。这有点繁琐,但它试图说明您可以使用任何具有静态存储期的对象的名称(因为将&应用于这样的对象将产生常量表达式)。 - M.M
显示剩余6条评论
1个回答

6
这正是由CWG 2091精确涵盖的内容:

According to 14.8.2.5 [temp.deduct.type] paragraph 17,

If P has a form that contains <i>, and if the type of the corresponding value of A differs from the type of i, deduction fails.

This gives the wrong result for an example like:

template<int &> struct X;
template<int &N> void f(X<N>&);
int n;
void g(X<n> &x) { f(x); }

Here, P is X<N>, which contains <i>. The type of i is int&. The corresponding value from A is n, which is a glvalue of type int. Presumably this should be valid.

I think this rule means to say something like,

If P has a form that contains <i>, and the type of i differs from the type of the corresponding template parameter of the template named by the enclosing simple-template-id, deduction fails.

如@dyp所指出的,[temp.deduct.type]/17应该更加宽容。在您的例子中,FooClass<F> (F)中的参数没有引用类型 - 它是类型为foo的lvalue。 FooClass的模板参数是一个引用。DR去年已经解决了。

有没有办法绕过这个问题,让这个例子能够正常工作? - Paweł Bylica

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