ошибка: функциональное приведение к типу массива при попытке обнаружить, если std :: cout << t;является действительным - PullRequest
0 голосов
/ 03 октября 2018

По комментарию к этому ответу Я хотел бы написать (в C ++ 11)

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

, чтобы отключить / включить функцию-член в зависимости от 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 был конструируемым по умолчанию, и с тех пор я поворачиваюсь в кругах.Когда у меня есть значение, я могу легко test, если std::cout << t; допустим, но только с одним типом я понятия не имею, как правильно реализовать has_out_op.

Как определить, существует ли соответствующая перегрузка для std::cout << t; только для данных decltype(t)?

Обратите внимание, что я уже знаю, как отключить / включить B::operator<<правильно, но из вежливости я все еще борюсь с правильным has_out_op.

1 Ответ

0 голосов
/ 03 октября 2018

std::declval<T>() на помощь:

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

Обратите внимание, что поскольку для declval не существует определения, его можно использовать только в неоцененных контекстах;я

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

, хотя мне было бы интересно, если бы было более простое решение для 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, "");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...