浅谈 c++ adl 机制

namespace f1{
	namespace f2{
		struct cow{
			friend void solve(cow){cout<<"f1::f2::cow";}
		};
	}
	void solve(f2::cow){cout<<"f1\n";}
	namespace f2{
		void solve(cow){cout<<"f1::f2\n";}
	}
}
void solve(f1::f2::cow){cout<<"::";}
namespace g1{
	void solve(f1::f2::cow){cout<<"g1";}
	namespace g2{
		void solve(f1::f2::cow){cout<<"g1::g2";}
		void print(){solve(f1::f2::cow{});}
	}
}

相信看到这段代码,很多人都会感到害怕,这个 print 究竟会输出什么呢?其实这段代码会 CE

先说说什么是 adl,很好理解,就是调用的函数会在参数的命名空间里查找。比如我有个 std::string b,我要统计里面有多少个空格,那就是 std::count(b.begin(),b.end(),' '),返回值就是空格的数量。
看这么一段代码:

namespace ff{
	struct cow{};
	cow operator+(const cow &x,const cow &y){
		return cow{};
	}
}
ff::cow solve(){
	ff::operator+(ff::cow{},ff::cow{});
	return ff::cow{}+ff::cow{};
}

假如没有 adlsolve 里面的加法必须以第一种方式显式调用这样才能调用到这个函数,但是有 adl 的情况下,ff::operator+ 可以直接由 ff::cowadl 到。让很多情况方便了不少。

接下来看看上面那段代码,首先排除的是 ::solveg1::solve,都被 g1::g2::solve 给遮盖了(局部屏蔽全局),f1::solve 由于 adl 只会往外找同一层命名空间,所以并不会被 adl 到。这个时候 g1::g2::solve(和函数本身就在同一命名空间) 和 f1::f2::solve(通过 adl 找到) 和 f1::f2::cow::solve(类内友元,也能通过 adl 找到)具有同等地位,所以就会导致 CE。

至于 adl 的实际价值就是节省码量,拓宽函数的寻找范围,很多本来要 std:: 的都可以省略。

endl(std::cout<<a[2]);
flush(std::cout<<"! 3\n");// cout 作参数
std::cout<<std::endl;// 注意这里的函数是 operator<<
operator<<(std::cout,std::endl);// 注意这里的函数是 operator<<
(std::endl)(std::cout<<"4\n");// 加上括号,没法 adl,必须写 std::endl
std::pair<int,int>a[3];
sort(a,a+3);// 指针也可以 adl
posted @ 2022-11-11 20:33  蒟酱  阅读(426)  评论(0编辑  收藏  举报