C++: double column(class access control qualifier) inhibits type deduction

在channel 9 上看Stephan T. Lavavej讲Core C++(上channel 9搜索 core C+  part II 即可看到),学到了点trick:

如果我们写一段这样的代码,让编译器帮我们做template type deduction:

1 template <typename T> void meow(T val, function<void (T)> f){
2     f(val);
3 }
4 
5 int main(){
6     meow(1729,[](int x){cout << "lamda " << x << endl;});
7 }

不会通过编译。因为当编译器将lamda [](int x){cout << "lamda " << x << endl;} 向 function<void (T)> 做template type deduction的时候,会失败,因为C++在做template type deduction的时候不会同时做类型转换。即使那个lamda可以通过类型转换成 function<void (T)> ,但是编译器在这里只会做类型推导,不会同时也做隐式类型转换。

所以,基于以上原因,如果我们要使其能顺利地类型转换通过编译,就应该这样写:

 1 template <typename T> void meow(T val, function<void (T)> f) {
 2     f(val);
 3 }
 4 
 5 int main() {
 6     //这里发生了类型转换
 7     function<void (int)> fxn = [](int x) { cout << "lamda " << x << endl; };
 8 
 9     //很自然的template type deduction,因为fxn的类型就是functioin<void (T)>, 这样,T就会被推导为int
10     meow(1729, fxn); 
11 }

说好的trick呢 ? 在这里:

 1 template <typename T> struct Identity {
 2     typedef T type;
 3 };
 4 
 5 template <typename T> void meow(T val, 
 6     typename Identity<function<void (T)>>::type f) {
 7     f(val);
 8 }
 9 
10 int main(){
11 //我可以在这里直接用lamda了 !!Why ?!!!
12 meow(1729,[](int x)(count << "lamda " << x << endl;});
13 }

虽然这段代码有点丑(为了展示这个trick而有意为之),但是还是很有技术含量的。

首先,来看一些编译器在做argument type deduction的流程:  首先是    T val   , 由于传入了一个1729, 为int类型,所以此时 T 就“有可能“被推导为int。接着,编译器又看到 typename Identity<function<void (T)>>::type f ,这时候他就不会做类型推导了,原因就是这篇文章题目所说的double column(class access control qualifier) inhibits  type deduction当编译器看到 typename Identity<function<void (T)>::type f 的时候, 由于 Identity<function<void (T)>::type 前面有个 typename ,所以他知道 Identity<function<void (T)>::type 是一个类型,然后当编译器想进一步推导的时候,它看到了 type 这个东西前面有一个 :: (access control qualifier),表明 type 是某个namespace 或某个class里面的东西,所以它就不会再进行类型推导了,也就是说这个 :: 阻止了编译器进一步进行类型推导(所谓 double column inhibits type deduction)。所以,编译器的类型推导到这里就结束了。

那么, Identity<function<void (T)>> 里面的 T 呢? 由于类型推导结束了,那么T的类型自然也就确定了咯,就是在推导 T val 的时候所确定为的 int 。这时候,由于类型推导结束了,那么函数 meow 的参数类型就可以确定为: (int , typename Identity<function<void (int)>>::type ) 了( typename Identity<function<void (T)>>::type 变成了 typename Identity<function<void (int)>>::type ),那么,将lamda  [](int x)(count << "lamda " << x << endl;} 传进去就可以正常地发生隐式类型转换了(由lamda转换成 Identity<function<void (int)>>::type ),所以就可以成功调用了。

( source: All the code above are from Stephan T. Lavavej

原文地址:https://www.cnblogs.com/walkerlala/p/5320251.html