gpt4 book ai didi

c++ - 模板中的友元函数(为什么这在 Visual Studio 中失败但在 GCC 和 Clang 中失败)

转载 作者:太空狗 更新时间:2023-10-29 20:09:25 26 4
gpt4 key购买 nike

鉴于以下内容(精简并设法突出问题):

#include <utility>

namespace Generic
{
class Whatever
{
public:
// ISSUE1 (member "swap()" has same name as non-member template)
void swap()
{
}
};

// Forward declaration of class template "Test"
template <class>
class Test;

// Prototype of function template "swap()" for class template "Test"
template<class T>
void swap(Test<T> &, Test<T> &);

/////////////////////////////////////////////////////////////////
// Class template "Test"
/////////////////////////////////////////////////////////////////
template <class T>
class Test : public T
{
public:
// Default constructor
Test() = default;

// Move constructor
Test(Test &&test)
: BaseClass(std::move(test))
{
}

// Assignment operator
Test& operator=(Test test)
{
// Note that the "Generic:" prefix here has no impact on the results
Generic::swap(*this, test);

return (*this);
}

private:
using BaseClass = T;

// ISSUE2 (qualified call - prefixing with "Generic:")
friend void Generic::swap<T>(Test &, Test &);
};

/////////////////////////////////////////////////////////////////
// Canonical swap function for class "Test" just above
/////////////////////////////////////////////////////////////////
template<class T>
void swap(Test<T> &, Test<T> &)
{
}

} // namespace Generic

int main()
{
using namespace Generic;
Test<Whatever> test1;
Test<Whatever> test2;
test2 = std::move(test1);

return 0;
}

谁能看出它不应该编译的任何原因。请特别注意评论中的 ISSUE1 和 ISSUE2。这些都会影响结果。 ISSUE1 和 ISSUE2 有 4 种组合来尝试让事情正常进行(见下表),尽管我知道另一种纠正方法,但这 4 种组合是我想要关注的。请注意,所有 4 种组合都可以在 GCC 和 Clang 中干净地编译,但只有第 4 项可以在 Visual Studio 2017(最新版本)中干净地编译。其他组合(1 到 3)失败并在下面的 RESULT 列中看到错误(编译器在所有 3 种情况下都引用了 ISSUE2 行的问题):

   ISSUE1                               ISSUE2                          RESULT
------ ------ ------
1) Leave unchanged Leave unchanged 'Generic::Test': use of class template requires template argument list
'Generic::swap': not a function

2) Leave unchanged Remove "Generic:" qualifier syntax error: missing ';' before '<'
'swap': illegal use of type 'void'
'Generic::swap': 'friend' not permitted on data declarations
'Generic::swap': redefinition; previous definition was 'function'
unexpected token(s) preceding ';'

3) Comment out member "swap()" Leave unchanged 'Generic::Test': use of class template requires template argument list
'Generic::swap': not a function

4) Comment out member "swap()" Remove "Generic:" qualifier Works!!!

是 Visual Studio 有问题还是 GCC 和 Clang 有问题(根据我对合格/不合格名称查找规则、ADL 等的理解,前者似乎是这种情况)。谢谢。

最佳答案

呵呵,找到博客了: Two-phase name lookup support comes to MSVC .

一些相关摘录:

The original design of templates for C++ meant to do exactly what the term “template” implied: a template would stamp out families of classes and functions. It allowed and encouraged, but did not require, early checking of non-dependent names. Consequently, identifiers didn’t need to be looked up during parsing of the template definition. Instead, compilers were allowed to delay name lookup until the template was instantiated. Similarly, the syntax of a template didn’t need to be validated until instantiation. Essentially, the meaning of a name used in a template was not determined until the template was instantiated.

In accordance with these original rules, previous versions of MSVC did very limited template parsing. In particular, function template bodies were not parsed at all until instantiation. The compiler recorded the body of a template as a stream of tokens that was replayed when it was needed during instantiation of a template where it might be a candidate.

文章然后继续发布一些与n.m.’s minimal example 非常相似的代码.

It’s important to note that overloads declared after the point of the template’s definition but before the point of the template’s instantiation are only considered if they are found through argument-dependent lookup. MSVC previously didn’t do argument-dependent lookup separately from ordinary, unqualified lookup so this change in behavior may be surprising.

最后,关于使 MSVC 使用更新的两阶段模板解析的注意事项:

You’ll need to use the /permissive- conformance switch to enable two-phase lookup in the MSVC compiler included with Visual Studio 2017 “15.3”. Two-phase name lookup drastically changes the meaning of some code so the feature is not enabled by default in the current version of MSVC.

关于c++ - 模板中的友元函数(为什么这在 Visual Studio 中失败但在 GCC 和 Clang 中失败),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46469558/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com