kla*_*aus 20 c++ boost argument-dependent-lookup c++17 c++20
我有一个带有继承和shared_ptr
来自 boost 库的简单代码。使用标准 c++20,代码可以正常编译。函数调用static_pointer_cast
和dynamic_pointer_cast
编译无需预先boost::
命名空间——这些函数调用之所以有效,是因为 ADL(参数相关查找)。
但对于标准 c++17,代码将无法编译。我认为 ADL 没有实现,或者实现方式不同。但是,如果我添加using namespace std
,代码就可以正常编译。我的问题是:与库的函数调用std
有什么关系?boost
这是在线编译器,因此您可以通过注释行中和注释行来进行操作using namespace std;
: https: //godbolt.org/z/cz8Md5Ezf
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
// using namespace std;
class Animal {
public:
Animal()
{}
virtual ~Animal()
{}
void speak()
{
std::cout << "I am an animal\n";
}
};
class Dog : public Animal {
public:
Dog()
{}
void bark()
{
std::cout << "Gheu --> ";
}
void speak()
{
bark();
Animal::speak();
}
};
typedef boost::shared_ptr<Animal> AnimalPtr;
typedef boost::shared_ptr<Dog> DogPtr;
int main()
{
AnimalPtr ap = boost::make_shared<Animal>();
DogPtr dp = boost::make_shared<Dog>();
AnimalPtr ap1 = static_pointer_cast<Animal>(dp);
DogPtr dp1 = dynamic_pointer_cast<Dog>(ap1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果您在想,“好吧,如果使用命名空间 std 可以消除错误,那么这些指针转换调用必须来自 std 库。” 我也是这么想。但是通过gdb查看,我发现不,with using namespace std
,这些函数肯定是从boost库调用的。
use*_*522 22
当编译器<
在表达式中的标识符后面看到 a 时(例如 in static_pointer_cast<Animal>(dp)
),它需要确定它是否<
引用关系型 less 运算符,或者它是否是模板参数列表的开头。
如果通过通常的非限定名称查找(不是 ADL)找到模板,则假定是后者。但是如果没有找到模板怎么办?
在 C++20 之前,如果查找没有找到模板,则假定该名称不引用模板,因此以下<
是 less 运算符。
在你原来的情况下,这是没有意义的。例如,没有任何东西static_pointer_cast
可以作为操作数来引用<
。因此,根据编译器的不同,它会失败并显示或多或少清晰的错误消息。
编译器using namespace std;
可能会隐式包含std::static_pointer_cast
(来自<memory>
)您显式包含的标头之一(无法保证),或者 boost 标头可能包含<memory>
. 如果发生这种情况,那么非限定查找static_pointer_cast
将找到它,并且因为它是一个模板,<
所以它会被视为启动模板参数列表而不是关系运算符。那么很明显,整个表达式是一个带有模板参数列表的非限定函数调用。
从 C++20 开始,如果查找没有找到任何内容或根本没有找到任何函数,则还假定<
名称后面的 a 引入了模板参数列表。
通过解释为模板参数列表和函数调用,将完成正常的非限定名称查找和非限定函数调用的 ADL,这会找到两者boost::shared_pointer_cast
(通过 ADL)并且std::shared_pointer_cast
如果您正在使用using namespace std;
,但因为您正在传递boost::shared_ptr
版本std
,这需要参数std::shared_ptr
,将不可行,并且boost
版本将始终由重载决议选择。这部分在 C++20 中没有变化。
请注意,这是 C++20 中的重大更改。在某些不寻常的情况下,您可能希望<
在函数名称之后实际引用关系运算符,而现在需要将函数名称加上括号。有关示例,请参阅[diff.cpp17.temp] 。
归档时间: |
|
查看次数: |
996 次 |
最近记录: |