【发布时间】:2020-06-30 14:28:46
【问题描述】:
G++ 和 Clang++ 一致认为以下 sn-p 不是有效的 C++:
template<int dim, int rank>
struct Tensor {};
template<int dim>
double InnerProduct(Tensor<dim, 1> const &, Tensor<dim, 1> const &)
{ return 0.0; }
template<int dim>
double DoubleInnerProduct(Tensor<dim, 2> const &, Tensor<dim, 2> const &)
{ return 0.0; }
template<int dim, int rank>
class Field
{
private:
static double Dot(Tensor<dim, rank> const &u, Tensor<dim, rank> const &v) requires (rank == 1)
{ return InnerProduct(u, v); }
static double Dot(Tensor<dim, rank> const &u, Tensor<dim, rank> const &v) requires (rank == 2)
{ return DoubleInnerProduct(u, v); }
};
template class Field<2, 1>;
template class Field<2, 2>;
错误消息指出,即使是具有不满足约束的函数也会被实例化:
error: no matching function for call to ‘DoubleInnerProduct(const Tensor<2, 1>&, const Tensor<2, 1>&)’
22 | { return DoubleInnerProduct(u, v); }
我可以通过多种方式使其工作(例如,将 Dot 声明为模板,其默认参数等于 rank 并应用约束),但我希望它能够工作。
一般来说,我是否应该假设不能显式实例化具有依赖于模板参数的约束的成员函数的模板类?
【问题讨论】:
-
错误信息是什么?
-
观察(非解释):(A) 如果您只是声明
Dot重载,Field<2, 1>的显式实例化声明和Field<2, 2>编译成功。 (B) 即使不删除定义,您也可以显式声明对给定实例化可行的完整静态成员函数,而不仅仅是特定类模板的实例化声明:template double Field<2, 1>::Dot(Tensor<2, 1> const &, Tensor<2, 1> const &);。 -
[temp.explicit]/10 声明 “需要一个受约束模板的显式实例化才能满足该模板的相关约束。[...]” 这可能适用于此处,在您可以成功地为正确的
Dot重载提供明确的实例化定义(如我上面的评论所示)。 -
此外,[temp.explicit]/12 声明:“显式实例化定义命名类模板特化显式实例化类模板特化并且是显式实例化定义仅对那些已经在实例化点定义。”,这解释了为什么 Clang 和 GCC 接受
Field类模板的显式实例化定义,因为给定的(静态)成员函数实例化无效尚未定义。 -
您是否有理由明确实例化例如
template class Field<2, 2>;而不是仅仅声明一个变量Field<2, 2> foo?只是为了了解会发生什么吗?
标签: c++ language-lawyer c++20 c++-concepts explicit-instantiation