【问题标题】:MSVC 2017 - Bug - How to declare template member function of template class X as friend of nested class X::YMSVC 2017 - 错误 - 如何将模板类 X 的模板成员函数声明为嵌套类 X::Y 的朋友
【发布时间】:2019-02-06 07:36:47
【问题描述】:

我正在尝试获取一个使用 GCC 编译和运行的 cmake C++ 项目,以使用 MSVC 进行编译。我正在使用 VS 2017。

我不是代码的作者,我只是负责让它与 MSVC 一起编译。

项目很大,所以我不确定如何展示 MCVE。不过,我会尽量在这里解释:

我收到此错误:

这对应于下面sibling_iterator 类中的friend 声明。

但是,leftmost_output()node 的成员。

node 的定义附在下面(见下约 3/4):

我很确定这是related to the bug in VS related to nested template classes,因为sibling_iteratornode 嵌套在另一个模板类中。

我的问题是如何让整个节点类成为朋友而不是指定特定的成员函数?这可能会在任何其他建议中失败,这是最受欢迎的。

【问题讨论】:

  • 似乎很容易产生一个 MVCE。从上面的类中删除无关紧要的东西。在 main 中实例化兄弟迭代器。

标签: c++ class templates visual-c++ nested


【解决方案1】:

最小的可重现代码是:

#include <map>
template <class T, class T2>
struct relative_iterator : T {};

struct edge : public std::map<int, int>::iterator {};
using T_edge = edge;

class node {
public:

    template <class T_iterable, class T_content>
    class sibling_iterator : public relative_iterator<T_iterable, T_content>
    {
    public:
        friend sibling_iterator<edge, T_edge>  node::leftmost_output();
    //..
    };

    static sibling_iterator<edge, T_edge> leftmost_output();  // <--move up
} ;

有两种方法可以解决这个问题:

选项 1

leftmost_output()的定义移到class sibling_iterator上方

选项 2

node 设为从属名称。如果name 的别名依赖于T_iterable,则其查找将延迟到class sibling_iterator&lt;T_iterable, T_contents&gt; 实例化的时间。最简单的方法是使用标准中的标准实用程序:

class sibling_iterator : public relative_iterator<T_iterable, T_content>
{
public:
    static constexpr bool dependent_true = std::is_same<T_iterable,T_iterable>::value;
    using dependent_node = typename std::enable_if<dependent_true, node>::type;
    friend sibling_iterator<edge, T_edge>  dependent_node::leftmost_output();
};

选项 2.5

但是,如果您更喜欢定义自己的解决方案,您可以定义一个dependet_type&lt;T, Dependent&gt; 助手:

template <class T, class Dependent>
struct dependent_type
{
    using type = T;
};
template <class T, class Dependent>
using dependent_type_t = typename dependent_type<T, Dependent>::type;

并使用它:

template <class T_iterable, class T_content>
class sibling_iterator : public relative_iterator<T_iterable, T_content>
{
public:
    using dependent_node = typename dependent_type<node, T_iterable>::type;
    friend sibling_iterator<edge, T_edge>  dependent_node::leftmost_output();
//..
};

我认为这是最好的选择,因为它需要对现有代码库进行较少的更改。

选项 2.5.5

我会写一个更短的变体:

friend sibling_iterator<edge, T_edge> dependent_type_t<node, T_iterable>::leftmost_output()

这看起来很完美,因为它只需要对源代码进行最少的更改。如果它没有导致编译器崩溃,我会写的:

fatal error C1001: An internal error has occurred in the compiler.
(compiler file 'msc1.cpp', line 1469)

【讨论】:

    【解决方案2】:

    我收到此错误:

    错误 C2039:“leftmost_output”:不是“mv::graph::node”的成员

    [...]

    然而,leftmost_output() 是节点的成员。

    节点的定义在下面附加(见大约3/4的方式 下):

    显然,VC 编译器找不到node 的定义,因为它引用了不同范围内的东西。尝试将朋友声明移到嵌套 node 类的定义下方。

    【讨论】:

    • @D Drmmr 没想到,谢谢,我试试。
    猜你喜欢
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    • 2019-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多