error: functional cast to array type while trying to detect if std::cout << t; is valid

error: functional cast to array type while trying to detect if std::cout << t; is valid

由评论触发 我想写(在 C++11 中)a

template <typename T>
struct has_out_op { static const bool value = ???; }

到 dis/enable 一个成员函数取决于 std::cout << t; 对某些 T t 有效。我走到这一步...

#include <iostream>

struct can_convert_to_base{}; // but does not when there is a better match
struct base {base(can_convert_to_base);};

template <typename T> 
auto test(const T& t,can_convert_to_base) 
-> decltype( std::cout << t);

template <typename T> 
std::false_type test(const T& t,base);

template <typename T>
struct has_out_op {
    static const bool value = 
        !std::is_same<std::false_type,
                      decltype( test(T(),can_convert_to_base()) )
                      >::value;
};

struct A{};

int main() {
    std::cout << has_out_op<int>::value;   // prints 1
    std::cout << has_out_op<A>::value;     // prints 0
}

这似乎可行,但是当我将它用于我实际的目标时:

struct B {
    template <typename T>
    typename std::enable_if<has_out_op<T>::value,B&>::type operator<<(const T& t)  {
        std::cout << t;
        return *this;
    }
};
int main() {
    B b;
    b << "1";
}

我收到错误

prog.cc: In instantiation of 'const bool has_out_op<char [2]>::value':
prog.cc:25:60:   required by substitution of 'template<class T> typename std::enable_if<has_out_op<T>::value, B&>::type B::operator<<(const T&) [with T = char [2]]'
prog.cc:31:14:   required from here
prog.cc:17:67: error: functional cast to array type 'char [2]'
                           decltype( test(T(),can_convert_to_base()) )
                                                                   ^
prog.cc: In function 'int main()':
prog.cc:31:11: error: no match for 'operator<<' (operand types are 'B' and 'const char [2]')
         b << "1";
           ^

然后我意识到我的 has_out_op 要求 T 是默认可构造的,从那以后我就在兜圈子。当我有一个值时,如果 std::cout << t; 有效,我可以很容易地 test,但是仅凭类型我不知道如何正确实现 has_out_op

如何检测仅给定 decltype(t)std::cout << t; 是否存在匹配重载?

请注意,我已经知道如何正确 dis/enable B::operator<<,但出于礼貌,我仍在努力使 has_out_op 正确。

std::declval<T>() 救援:

Converts any type T to a reference type, making it possible to use member functions in decltype expressions without the need to go through constructors.

Note that because no definition exists for declval, it can only be used in unevaluated contexts; i

 ...
 decltype( test(std::declval<T>(),can_convert_to_base()) )
 ...

既然我们已经到了这里,您的解决方案就过于复杂了。我会这样做:

struct B {
    template <typename T, class = decltype(std::cout << std::declval<T>())>
    B& operator<<(const T& t)
    {
        std::cout << t;
        return *this;
    }
};

though I would be interested if there is a simpler solution for has_out_op

template <typename T>
struct has_out_op_impl
{
    template <class U, class = decltype(std::cout << std::declval<U>())>
    static auto foo(U) -> std::true_type;

    static auto foo(...) -> std::false_type;

    using Type = decltype(foo(std::declval<T>()));
};

template <class T>
struct has_out_op : has_out_op_impl<T>::Type
{};

struct A{};

int t1()
{
    static_assert(has_out_op<int>::value == true, "");
    static_assert(has_out_op<A>::value == false, "");
}