использование boost::hana для самоанализа

Я просматриваю примеры страницы справки потрясающей библиотеки boost::hana и не могу заставить пример самоанализа работать правильно.

Этот код предназначен для проверки во время компиляции, имеет ли объект определенную функцию-член или нет, а затем использует эту функцию-член или делает что-то по умолчанию.

Итак, я объявил эти два типа:

struct WithoutToString
{ };

struct WithToString
{
    std::string toString()
    {
        return "implements toString()";
    }
};

Это 1-я версия проверки с использованием hana::is_valid:

auto has_toString = hana::is_valid([] (auto&& obj) -> decltype(obj.toString()) { });

template <typename T>
std::string optionalToString1(T const& obj)
{
    return hana::if_(has_toString(obj),
        [] (auto& x) { return x.toString(); },
        [] (auto& x) { return "toString not defined"; }
    )(obj);
}

Это 2-я версия проверки с использованием hana::sfinae:

template <typename T>
std::string optionalToString2(T const& obj)
{
    auto maybeToString = hana::sfinae([](auto&& x) -> decltype(x.toString())
    {
        return x.toString();
    });

    return maybeToString(obj).value_or("toString not defined");
}

Используя обе версии, как это...

int main()
{
    WithToString obj;

    std::cout << optionalToString1(obj);
    std::cout << optionalToString2(obj);

    return 0;
}

... всегда показывает "toString не определен" вместо "реализует toString()".

Примечание: проверка obj на static_assert(has_toString(obj), "Does not implement toString()."); показывает правильное поведение.

Я что-то упускаю? Или это проблема компилятора (clang 5.0.1) или библиотеки (boost 1.66)?

Спасибо.


person Wum    schedule 26.03.2018    source источник


Ответы (1)


Ваши optionalToStringX функции занимают T const&. toString не является константной функцией-членом, поэтому она неприменима.

Жить на Coliru

#include <boost/hana.hpp>
#include <string>

namespace hana = boost::hana;

struct WithoutToString { }; 
struct WithToString { std::string toString() const { return "implements toString()"; } };

namespace v1 {
    //This is the 1st version of the check using hana::is_valid:
    auto has_toString = hana::is_valid([] (auto&& obj) -> decltype(obj.toString()) { });

    template <typename T>
        std::string optionalToString1(T const& obj)
        {
            return hana::if_(has_toString(obj),
                    [] (auto&& x) { return std::forward<decltype(x)>(x).toString(); },
                    [] (auto&&) { return "toString not defined"; }
                    )(obj);
        }
}

namespace v2 {
    //This is the 2nd version of the check using hana::sfinae:
    template <typename T>
        std::string optionalToString2(T const& obj)
        {
            auto maybeToString = hana::sfinae([](auto&& x) -> decltype(x.toString())
                    {
                    return x.toString();
                    });

            return maybeToString(obj).value_or("toString not defined");
        }
}

#include <iostream>
int main()
{
    WithToString with;
    WithoutToString without;

    std::cout << std::boolalpha << v1::has_toString(without) << std::endl;
    std::cout << std::boolalpha << v1::has_toString(with)    << std::endl;

    std::cout << v1::optionalToString1(without) << std::endl;
    std::cout << v1::optionalToString1(with)    << std::endl;
    std::cout << v2::optionalToString2(without) << std::endl;
    std::cout << v2::optionalToString2(with)    << std::endl;
}

Отпечатки

true
false
implements toString()
toString not defined
implements toString()
toString not defined
person sehe    schedule 26.03.2018
comment
@Wum Если честно, я этого не видел, я нашел его, просто покопавшись. Что заставило меня увидеть (после непосредственного тестирования has_toString, как вы все еще можете видеть в образце), просто заменить has_toString(obj) на std::true_type{} вот так: ошибка: передача 'const WithToString' в качестве аргумента 'this' приводит к отбрасыванию квалификаторов. Возможно, этот трюк поможет вам в следующий раз :) - person sehe; 27.03.2018