为啥此代码有效(具有无效非模板函数的 C++ 模板类)? [复制]
Posted
技术标签:
【中文标题】为啥此代码有效(具有无效非模板函数的 C++ 模板类)? [复制]【英文标题】:Why this code works (C++ template class with invalid non-template function)? [duplicate]为什么此代码有效(具有无效非模板函数的 C++ 模板类)? [复制] 【发布时间】:2020-12-08 15:58:12 【问题描述】:此 C++ 代码构建成功:
void h(int *)
template <typename T>
class A
public:
void f()
T *val;
h(val);
;
int main()
A<const int> a;
为什么?
不可否认A<const int>::f()
不行。
如果调用a.f()
,则无法按预期构建。
为什么A<const int>
的实例甚至允许存在呢?
我不确定 SFINAE 在这里如何应用。
不胜感激 C++ 标准报价或相关链接。
【问题讨论】:
您是否尝试过编译a.f()
的实际调用? (提示:不会那么顺利:ideone.com/geyI0b)
这能回答你的问题吗? Why are some functions within my template class not getting compiled?
成员函数不实例化,除非你使用,不使用也没问题。
@scohe001 "你试过编译a.f()
的实际调用吗?" 他们已经回答了这样的问题:“如果你调用a.f()
,它会失败按预期构建。"
不是A的错,是h的错。
【参考方案1】:
允许它存在是因为它的存在仍然有用。
考虑std::vector
,它具有resize
的单参数重载,默认构造新元素。绝对有用!但是,当您不打算以这种方式调整大小时,拥有某种不可默认构造的 std::vector
也很有用。强制所有成员函数可用,即使是用户不需要的函数,也会人为地限制类的适用性。
【讨论】:
我知道这是一个很好的语言功能,事实上我需要它,所以我很高兴它存在。我只是在寻找确认这是预期行为的官方声明。 @eepp - 在这种情况下,建议的重复项***.com/questions/23679525/… 回答了您的问题【参考方案2】:这里没有sfinae。如果我们仔细查看函数的声明,而不是它的实现:
template <typename T>
class A
public:
void f();
;
你可以看到没有什么可以告诉编译器这个函数不应该是重载决议的一部分。
如果我们添加一个包含表达式的返回类型,这是不同的:
template <typename T>
class A
public:
auto f() -> decltype(void(h(std::declval<T*>())));
;
那不一样。现在编译器需要解析h(T*)
来执行重载解析。如果替换失败(函数声明的实例化),则该函数不是集合的一部分。
至于代码为什么还能编译,看看这个:
void h(int *)
template <typename T>
class A
;
template<typename T>
void f()
T *val;
h(val);
int main()
A<const int> a;
-
不可否认
f(A<const int>)
不行
如果调用f(a)
,则无法按预期构建。
为什么A<const int>
的实例还允许存在呢?
现在答案应该很明显了:函数永远不会被实例化!
这同样适用于成员函数。如果你不使用它们,实例化所有成员函数是没有用的。
如果您要寻找确认此行为的官方声明,那么只需看看标准本身即可。
来自[temp.inst]/4(强调我的):
除非类模板或成员模板的成员是已声明的特化,当在需要成员定义存在的上下文中引用特化时,成员的特化会被隐式实例化或如果成员定义的存在影响了程序的语义;特别是,静态数据成员的初始化(以及任何相关的副作用)不会发生,除非该静态数据成员本身的使用方式要求该静态数据成员的定义存在。
【讨论】:
好的,非常感谢 Guillaume。我会接受这个,因为它非常完整并回答了我的问题。以上是关于为啥此代码有效(具有无效非模板函数的 C++ 模板类)? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
如图,c++里为啥template还能这样用啊?为啥template尖括号里有变量?(template<int x,int y>)