1

I am trying to get a cmake C++ project that compiles and runs with GCC to compile with MSVC. I am using VS 2017.

I'm not the author of the code I'm just tasked with making it compile with MSVC.

The project is large so I am unsure how can present a MCVE. However, I will try to explain as best as I can here:

I am getting this error:

Which correspinds to the friend declaration in the below sibling_iterator class.

However, leftmost_output() is a member of node.

The definition of node is appended below (see about 3/4 of the way down):

I'm pretty sure this is related to the bug in VS related to nested template classes as sibling_iterator and node are nested in a another template class.

My question is how could I make the whole node class a friend instead of specifying a specific member function? This might work failing at any other suggestions are most welcome.

cherry aldi
  • 327
  • 1
  • 10
  • Seems rather easy to produce an MVCE. Cut out the etraneous stuff from the classes above. Instantiate sibling_iterator in main. – john Aug 31 '18 at 10:02

2 Answers2

1

Smallest reproducible code is:

#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
} ;

There are two ways to combat this:

Option 1

Move the definition of leftmost_output() above class sibling_iterator

Option 2

Make node a dependent name. If there is an alias to name which is dependent on T_iterable, then its lookup will be delayed to the time when class sibling_iterator<T_iterable, T_contents> is instantiated. The simplest way is to use standard utilities in the standard:

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();
};

Option 2.5

But, if you prefer to define your own solution, you can define a dependet_type<T, Dependent> helper:

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;

And use it:

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();
//..
};

I think that this is the best alternative, since it requires less changes to the existing code-base.

Option 2.5.5

I would have written a shorter variant:

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

This looks perfect, since it requires minimal changes to the source code. I would have written it, had it not made the compiler crash:

fatal error C1001: An internal error has occurred in the compiler.
(compiler file 'msc1.cpp', line 1469)
Michael Veksler
  • 8,217
  • 1
  • 20
  • 33
0

I am getting this error:

error C2039: 'leftmost_output': is not a member of 'mv::graph::node'

[...]

However, leftmost_output() is a member of node.

The definition of node is appended below (see about 3/4 of the way down):

Apparently, the VC compiler doesn't find the definition of node, as it refers to something in a different scope. Try moving the friend declarations below the definition of the nested node class.

D Drmmr
  • 1,223
  • 8
  • 15