I am having trouble with a simple argument dependent lookup / template type inferencing issue

时间:2016-02-03 03:13:12

标签: c++ templates type-inference argument-dependent-lookup

I have this snippet of code and I do not understand why the std::cout line is not compiling... The argument lookup / template argument inferencing seems correct...

#include <iostream>

template<typename T>
struct A
{
    struct M1
    {
        T x;
    };
};

template<typename T>
std::ostream &operator<<(std::ostream &os, typename A<T>::M1 const &o)
{
    os << o.x;
    return os;
}


int main()
{
    A<int>::M1 a;

    std::cout << a; // This line fails

    return 0;
}

BTW I'm trying to do this without a declaring operator<<() as an inline function.

2 个答案:

答案 0 :(得分:3)

Your problem is that T is in a non deduced context. C++ will only simple pattern match, it will not invert possibly arbitrary type maps.

Imagine there was a specialization of A<void> that set using M1=A<int>::M1. Now both int and void are valid T for your <<. As the problem is intractible in general, C++ refuses to even try: you can only pattern match on direct template arguments of your argument types.

To do what you really want:

template<typename T>
struct A {
  struct M1 {
    T x;
    friend std::ostream& operator<<(std::ostream& os, M1 const& m1){
      return os << m1.x;
    }
  };
};

Learn to love Koenig operators.

答案 1 :(得分:2)

The template parameter T of your operator cannot be deduced. However, there is some workaround using some SFINAE magic:

#include <iostream>

template<typename T>
struct A {
    struct M1 {
        using type = T;
        T x;
    };
};

template<typename T, std::enable_if_t<std::is_same<T, typename A<typename T::type>::M1>::value, int> = 0>
std::ostream &operator<<(std::ostream &os, const T& o)
{
    os << o.x;
    return os;
}

int main()
{
    A<int>::M1 a;
    std::cout << a; // This line works
    return 0;
}