2

Edit2 : the previous solution caused some errors down the line so for now I am stuck with my member public.


Edit : I thought I had a solution, until I tried on Clang.

The error is about unableness to find a corresponding template.

However it solves itself if I add, before the first forward-declarations to the path function :

template<typename T, typename U=void>
Path<T> path(const T& obj);

But then GCC would not build it anymore so I fixed it with some macros...

#if defined(__clang__)
  template<typename T, typename U = void>
  Path<T> path(const T& obj);
#elif defined(__GNUC__)
  template<typename T, typename U>
  Path<T> path(const T& obj);
#endif

Here is a way to test the code : http://goo.gl/dafN8K


Original question

I found the following answers but they did not solve my problem :

Overloading friend operator << for template class

-> Not good for me because I want to befriend templates, not specializations with the class template parameters, and don't want to inline my code in this class.

Issue with friend template functions clang++ / msvc++ and enable_if

-> I don't want to change my function to have enable_if in the return type, it makes the code absolutely unreadable.

So, here is my minimal non working code. It works if m_path_cache is made public but of course I don't want a cache in my public interface...

#include <type_traits>
class IdentifiedObjectAbstract
{
};

template<typename T>
struct Path;

namespace ANamespace
{
template<typename T, std::enable_if_t<
             std::is_base_of<
                 IdentifiedObjectAbstract,
                 T
                >::value
             >* = nullptr
         >
Path<T> path(const T& obj);

template<typename T, std::enable_if_t<
             !std::is_base_of<
                 IdentifiedObjectAbstract,
                 T
                >::value
             >* = nullptr
         >
Path<T> path(const T& obj);
}


template<typename T>
class IdentifiedObject : public IdentifiedObjectAbstract
{   
    ////////
    // I need to befriend the first template function here.
    ////////

    private:
        mutable Path<T> m_path_cache;   
};

template<typename Object>
struct Path
{
};

namespace ANamespace
{
template<typename T, std::enable_if_t<
             std::is_base_of<
                 IdentifiedObjectAbstract,
                 T
                >::value
             >* = nullptr
         >
Path<T> path(const T& obj)
{
    return obj.m_path_cache;
}

template<typename T, std::enable_if_t<
             !std::is_base_of<
                 IdentifiedObjectAbstract,
                 T
                >::value
             >* = nullptr
         >
Path<T> path(const T& obj)
{
    return Path<T>{};
}
}

class A : public IdentifiedObject<A>
{};

void f()
{
     A a;
    auto path = ANamespace::path(a);

}

I also tried befriending functions such as :

template<typename U>
friend Path<U> path(const U& obj);

template<typename U, typename V>
friend Path<U> path(const U& obj);

template <typename U, std::enable_if_t<std::is_base_of<IdentifiedObjectAbstract, U>::value>*>
friend  Path<U> path(const U& obj);

template <typename U, std::enable_if_t<std::is_base_of<IdentifiedObjectAbstract, U>::value>* = nullptr>
friend  Path<U> path(const U& obj);

but to no avail.

Community
  • 1
  • 1
Jean-Michaël Celerier
  • 7,412
  • 3
  • 54
  • 75
  • If your only criterion for differentiating between the two overloads of `path` is inheritance, and given the way you're using `IdentifiedObject`, you could avoid using SFINAE in the first overload and just declare it like `template Path path(const IdentifiedObject& obj)`. This allows the corresponding `friend` declaration to match properly in Clang, GCC and MSVC. Another alternative is to use good old-fashioned tag dispatching, which will also work properly in all compilers and can handle complex criteria. I can put some sample code in an answer if that will help. – bogdan Oct 08 '15 at 23:54
  • I'll try it and it will certainly solve everything so yeah, you should post it as an answer ! – Jean-Michaël Celerier Oct 09 '15 at 08:32

0 Answers0