c++ - friend 模板参数相关查找

标签 c++ templates visual-c++ friend argument-dependent-lookup

已知在类范围内定义的友元函数可以通过参数相关查找找到,所以我们必须在友元函数类型中使用类类型,但是如果我们在类之外定义友元函数,它的函数参数可以留空. 那么这对于模板友元是如何工作的,如果我们在类之外进行专门化,它应该像在类范围之外定义的普通友元函数一样可见。

#include <iostream>    
class A
{
public:
        A()
         : x(20)
        {}
        template <typename T>
        friend void foo()
        {
               std::cout << "Primary Template" << std::endl;
        }
        friend void goo();
private:
        int x;
};

void goo() 
{
    std::cout << "some goo" << std::endl;
}


template <>
void foo<int>()
{
        std::cout << "specialization" << std::endl;
}

int main()
{
        A a;
        foo<int>(); //  VS 2012 gives error C3767: 'foo': candidate function(s) 
                    // not accessible
                    //  'foo'  [may be found via argument-dependent lookup]
        goo();      // OK
}

那么为什么 goo 是可见和可访问的,而 foo 对 int 的专门化却不是? VisualStudio 2012 给出错误“'foo':候选函数不可访问,'foo' [可以通过参数相关查找找到]”。顺便说一句,GCC 编译代码没有错误。标准中是否有任何限制,或者这只是编译器问题?

最佳答案

我认为 Clang 在这里可能是正确的。考虑两件事:

§14.7.3/8 [temp.expl.spec],稍微删减示例:

A template explicit specialization is in the scope of the namespace in which the template was defined. [Example:

namespace N {
    template<class T> class X { /* ... */ };
    template<> class X<int> { /* ... */ }; // OK: specialization 
                                           // in same namespace
}
template <> class N::X<double> { /* ... */ }; // OK: specialization
                                              // in enclosing namespace

—end example ]

但是,有问题的友元函数,foo ,根据 §11.3/7 [class.friend](强调我的)住在:

A friend function defined in a class is in the (lexical) scope of the class in which it is defined.

提供 foo 的特化, 它必须在 A 中的词法范围——我认为这是不可能的。你的foo<int>特化在错误的范围内。

请注意,这仅适用于在类中定义函数的情况。以下代码在 Clang 上为我编译和运行得很好,因为现在 goo不在 M 中的范围:

#include <iostream>
struct M
{
    template <typename T>  
    friend void goo();     // only declared, not defined
};

template <typename T>
void goo() { 
    std::cout << "full" << std::endl;
}

template <>
void goo<int>() {
    std::cout << "explicit" << std::endl;
}

int main()
{
    goo<int>(); // prints explicit
}

可见性规则在 §7.3.1.2/3(强调我的)中建立:

The friend declaration does not by itself make the name visible to unqualified lookup (3.4.1) or qualified lookup (3.4.3). [ Note: The name of the friend will be visible in its namespace if a matching declaration is provided at namespace scope (either before or after the class definition granting friendship). —end note ]

因此,在这个更简单的示例中:

struct M {
    template <typename T> friend void foo(T ) { }
};

fooM 中定义, 所以它住在它的 M 中的词法范围。没有foo的“匹配声明”在M之外所以它应该只在 ADL 中可见(§3.4.2/4,强调我的):

When considering an associated namespace, the lookup is the same as the lookup performed when the associated namespace is used as a qualifier (3.4.3.2) except that

(4.1) - Any using-directives in the associated namespace are ignored.

(4.2) - Any namespace-scope friend functions or friend function templates declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup (11.3).

int main() {
    foo(M{}); // compiles correctly on both GCC and Clang
    foo(0);   // should fail. Clang complains about "use of undeclared identifier 'foo'"
              // but GCC 4.9.2 allows it! (update: fixed in 5+)
}

所以我重申我的第一句话:我认为 Clang 在这里可能是正确的。

关于c++ - friend 模板参数相关查找,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27917680/

相关文章:

c++ - 如何保证进程调用malloc()时立即分配物理内存?

c++ - 通过模板函数调用类函数

c++ - 在 Visual Studio 2013 中将 libcurl 库静态链接到我的项目(一个 dll)

c++ - 将引用显式传递到不期望引用的函数模板中会导致问题吗?

c++ - 在另一个 VS 项目中引用函数模板的显式实例化时出现 LNK2019 错误

c++ - 糟糕的串行端口/USB 代码 (C++) - 修复建议?

c++ - 关键字 'template' 混淆了 MSVC

c++ - 如何在私有(private)继承中调用父成员?

c++ - SFML Project microsoft visual express 2010 到 2012 兼容性问题

c++ - 学习 MPI for C++ 的最佳教程是什么?