2015-05-11 18 views
4

我想使用std :: initializer_list作为使用参数依赖查找(ADL)的函数中的参数。但我没有得到它的工作,我不明白为什么。以下是最小的失败示例:initializer_list和参数依赖查找

#include <initializer_list> 
    #include <iostream> 

    class Foo { 
    public: 
     inline friend void bar(std::initializer_list<Foo> v) { 
     std::cout << "size = " << v.size() << std::endl; 
     } 
    }; 

    void baz(std::initializer_list<Foo> v) { 
     std::cout << "size = " << v.size() << std::endl; 
    } 

    int main(){ 
     Foo a; 
     //bar({a,a}); // error: use of undeclared identifier 'bar' 
     baz({a,a}); // works 

     return 0; 
    } 

如上所示,等效的全局函数工作得很好。为什么上述不起作用?

我在OS X 10.10上使用了clang。

+0

您正在定义类中的朋友实现。它需要在外面,请参阅[this](http://stackoverflow.com/a/7785963/2297365)。这是一个[工作示例](http://coliru.stacked-crooked.com/a/b8fd514c67458c99)。 – huu

+0

@huu:这是不相关的,如果将类型和函数移动到名称空间,您会注意到ADL不会找到它们,无论该函数是在类内还是外部定义的。 –

+0

'template std :: initializer_list il(std :: initializer_list x){return x;} '是一个有点危险的解决方法。 'bar(il({a,a}))'起作用。危险因为支持数组的寿命问题。 – Yakk

回答

8

我认为,问题是,子表达式 { a, a }并没有真正有一个类型,因此它并没有相关的类型或命名空间而这又意味着,ADL不踢。如果你有一个函数在全局命名空间中,普通查找会找到它,并且它会发现{ a, a }可以匹配作为std::initializer_list<Foo>的初始值设定项的函数调用。

语法{ a, a }称为支撑-INIT列表和它是不是真的在语言的表达(或子表达式)。

+3

作为一个说明,'auto'的例外是'std :: initializer_list'的推导。 'auto param = {a,a};酒吧(param);'工作。 –

+0

很好的答案!我接受了这个。谢谢! – Joel

2

当编译器看到bar({a,a}),它不知道的参数的类型,因此它在全局命名空间(::)搜索bar,和其他地方。如果您将该行更改为Foo{a,a},则它知道参数是Foo,因此还会搜索Foo类的函数。