C++ 与SFINAE结合使用时静态过载
我尝试在Visual Studio 2013中编译以下程序,得到了C++ 与SFINAE结合使用时静态过载,c++,sfinae,C++,Sfinae,我尝试在Visual Studio 2013中编译以下程序,得到了C2686:无法重载静态和非静态成员函数错误 #include <iostream> #include <type_traits> struct foo { template<bool P> static std::enable_if_t<P> bar() { std::cerr << "P is true\n"; } template&l
C2686:无法重载静态和非静态成员函数
错误
#include <iostream>
#include <type_traits>
struct foo
{
template<bool P>
static std::enable_if_t<P> bar()
{
std::cerr << "P is true\n";
}
template<bool P>
std::enable_if_t<!P> bar()
{
std::cerr << "P is false\n";
}
};
int main()
{
foo f;
f.bar<true>();
}
在我看来,Visual Studio 2013在这两个案例中有一个是错误的,但我希望语言律师能给出明确的答案。令人惊讶的是,MSVC是正确的。(我知道,震惊。)[过载]/p1-2: 1并非所有函数声明都可以重载。这里指定了那些不能重载的。A. 如果程序在同一范围内包含两个这样的不可重载声明,则该程序是格式错误的。[注:此 限制适用于范围内的显式声明,以及此类声明和所做声明之间的显式声明 通过使用声明(7.3.3)。它不适用于因名称而制造的函数集 查找(例如,由于使用指令)或重载解析(例如,针对操作员功能)。-结束注释] 2某些函数声明不能重载:
- 不能重载仅在返回类型上不同的函数声明
- 具有相同名称和名称的成员函数声明
如果参数类型列表中的任何一个是
成员函数声明,则不能重载该列表(9.4)。同样,成员函数 具有相同名称的模板声明,相同 参数类型列表,如果同一模板参数列表中的任何一个是静态
成员函数模板,则不能重载它们 宣言。[……]静态
- [……]
bar()
声明具有相同的名称、相同的参数类型列表和相同的模板参数列表,其中至少有一个是静态的
,因此不能重载。Background
我认为VisualStudio在这种情况下是不正确的
[1] 编译函数调用的状态分为两个步骤:名称查找,然后是重载解析(如果需要)(我们将在本例中看到这是不必要的)
名称查找生成候选函数的列表。名称查找由两个步骤组成,依赖于参数的查找,然后是模板参数推断
如果名称查找生成多个可能的函数调用,则会发生重载解析以确定要调用的正确函数
SFINAE是一种元编程技术,用于在模板参数推导的子步骤中操作候选函数集[2]。SFINAE在模板参数替换期间导致替换错误,从而阻止将所述函数添加到候选集[3]
例子
让我们手工编译这个例子
- [1]
- [2]
- [3] http://en.cppreference.com/w/cpp/language/sfinae
<代码>吗?尝试将其写成
typename std::enable_if::type
。我记得2013有一些C++11支持(对库的支持非常广泛),但没有C++14。哦,当一个人想到这些年的时候,这是理所当然的!它在gcc和clang@Cheers中编译成功是的,VC2013支持std::enable_if_t
。通过删除第一次重载声明中的静态
,我上面的程序可以正确编译。@CraigM.Brandenburg:谢谢!今天也学到了一些新东西我编辑了我的问题,将静态
案例与重载返回类型进行对比,在没有SFINAE的情况下,标准也禁止重载返回类型,但与静态
案例不同,使用SFINAE时编译为OK。由于这种差异,我觉得你引用的标准中的段落不足以解释发生了什么。此外,它没有解释为什么,正如@Stephen在上面的评论中指出的那样,gcc和clang支持static
案例。@CraigM.Brandenburg重载返回类型对于函数模板来说是好的,因为bullet 2.1(我刚刚添加到答案中)只禁止具有不同返回类型的函数,而不是函数模板(其签名包括返回类型-请参见[defns.signature.temp]和[defns.signature.member.temp])。至于GCC和Clang的行为,要么是错误,要么是故意不合规。Bullet 2.2明确禁止此处讨论的重载。感谢您澄清您的答案。此处的关键问题是SFINAE是否排除了两个函数定义在同一重载集中。如果是,则您引用的重载规则可能不适用因此,问题是:SFINAE如何与重载规则相关联?@CraigM.Brandenburg它们是一些正交的东西。[over.load]中的规则不适用于重载集的构建;它们使任何“在同一范围内包含两个这样的非重载声明”的程序都格式错误,而不管为任何给定调用构造的重载集是否会导致实际的歧义。有趣。因此禁止使用重载
#include <iostream>
#include <type_traits>
struct foo
{
template<bool P>
std::enable_if_t<P> bar()
{
std::cerr << "P is true\n";
}
template<bool P>
std::enable_if_t<!P, int> bar()
{
std::cerr << "P is false\n";
return 42;
}
};
int main()
{
foo f;
f.bar<true>();
}