MSVC 2017 - Ошибка - Как объявить функцию-член шаблона класса X как друга вложенного класса X :: Y - PullRequest
0 голосов
/ 31 августа 2018

Я пытаюсь получить проект Cmake C ++, который компилируется и запускается с GCC для компиляции с MSVC. Я использую VS 2017.

Я не автор кода, мне просто поручено сделать его компиляцией с MSVC.

Проект большой, поэтому я не уверен, как можно представить MCVE. Однако я постараюсь объяснить здесь как можно лучше:

Я получаю эту ошибку:

Что соответствует объявлению friend в классе sibling_iterator ниже.

Однако leftmost_output() является членом node.

Определение node добавлено ниже (см. Примерно 3/4 пути вниз):

Я почти уверен, что это связано с ошибкой в ​​VS, связанной с вложенными шаблонными классами , поскольку sibling_iterator и node вложены в другой шаблонный класс.

Мой вопрос заключается в том, как сделать весь класс узла другом, а не указывать конкретную функцию-член? Это может работать без каких-либо других предложений.

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

Наименьший воспроизводимый код:

#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<T_iterable, T_contents>. Самый простой способ - использовать стандартные утилиты в стандарте:

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<T, Dependent> помощник:

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)
0 голосов
/ 31 августа 2018

Я получаю эту ошибку:

ошибка C2039: 'leftmost_output': не является членом 'mv :: graph :: node'

[...]

Однако leftmost_output () является членом узла.

Определение узла добавлено ниже (см. Примерно 3/4 пути вниз):

Видимо, компилятор VC не находит определения node, поскольку он ссылается на что-то в другой области видимости. Попробуйте переместить объявления друзей ниже определения вложенного класса node.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...