如何在不知道 class 是否为模板的情况下调用模板化成员函数?

How do I call a templated member function without knowing whether or not the class is a template?

假设我有以下宏:

#define CALL_FOO(x) x.foo<int>();

这个宏将调用带有模板参数 int 的模板化 foo 函数,只要 x 本身不是模板类型,它就会编译。如果是,我需要定义该宏的第二个变体来处理模板类型:

#define CALL_FOO_TEMPLATED(x) x.template foo<int>();

我如何创建一个宏来调用模板成员函数 foo 而不管 x 是否是从属名称?

(首先,从不; 放在宏的末尾。它会在某些 if 调用中中断。)

我认为您可以随时安全地将 template 放在 foo 前面。有时它是必需的。有时它是可选的。但我不认为在模板前立即使用 template 是不被允许的。

#define CALL_FOO(x) x.template foo<int>()

您正在寻找的答案,在 [temp.names] 中,需要 template 时:

When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template.

但是虽然对引用的名称有限制:

A name prefixed by the keyword template shall be a template-id or the name shall refer to a class template.

其中"dependence-ness"没有任何限制:

[ Note: As is the case with the typename prefix, the template prefix is allowed in cases where it is not strictly necessary; i.e., when the nested-name-specifier or the expression on the left of the -> or . is not dependent on a template-parameter, or the use does not appear in the scope of a template. —end note]

所以下面的代码总能正常编译:

struct X
{
    template <typename >
    void foo() { }
};

int main()
{
    X{}.template foo<int >(); // template keyword not strictly necessary
}

真正的答案是:不要为这样的事情使用宏。只需写出函数调用即可。以后大家会感谢你的。额外的好处是在调用站点,您知道是否需要 template 关键字,因此您可以在需要的地方精确使用它。

对于 C++11,只需无条件地使用 template。对于 C++03,大多数编译器甚至会接受 template 非依赖名称,但可能会发出警告。如果你需要迎合其他编译器,或者警告不可接受,你可以尝试这样:

template<class X>
void CALL_FOO(X& x)
{
  x.template foo<int>();
}
template<class X>
void CALL_FOO(const X& x)
{
  x.template foo<int>();
}

这不允许您传递 foo 返回的值。如果它是固定类型,则添加起来很容易。否则你需要某种形式的 decltype,它不是 C++03 的一部分,但你可以尝试 Boost.Typeof.