C ++ 14: Templates Boost Stati c посетитель - PullRequest
0 голосов
/ 06 апреля 2020

Я реализую шаблонный посетитель c, который я хочу использовать для возврата типа. Для посетителя будет задан шаблон одного типа, и он должен выдать ошибку для всех остальных файлов.

#include <iostream>

#include <stdexcept>


#include <boost/variant/variant.hpp>
#include <boost/variant/static_visitor.hpp>

using namespace std;

template<class Type>
struct GetValue : public boost::static_visitor<Type>
{
    template<class Other>
    Type operator()(Other&& o) const
    {
        cout << "called some exception" << endl;
        throw std::runtime_error("error");
    }
    Type operator()(Type& t) const
    {
        cout << "called correct" << endl;
        return std::forward<Type>(t);
    }
};

template<class S>
struct Foo : public boost::variant<S, std::string>
{
    template <class Type>
    Foo(Type&& t)
     : boost::variant<Type, std::string>(std::forward<Type>(t))
     {}

    S operator*() const
    {
        return boost::apply_visitor(GetValue<S>{}, *this);
    }
};

int main()
{
    Foo<int> f = 5;
    auto foo = *f;
    return 0;
}

Из того, что я понимаю, и извините, если я пропущу терминологию, мой первый оператор - это идеальная ссылка для пересылки и все звонки будут отправлены туда. Тем не менее, мой тип шаблона «Тип» уже был расширен после создания экземпляра GetValue, и, следовательно, ни один вызов, который я хочу, не соответствует второму, возвращающему тип.

Какое определение мне нужно, чтобы, когда я применяя посетителя, вызывается нужная мне функция вместо всего, что ссылается на шаблон по умолчанию.

Это MVCE: https://godbolt.org/z/T5gd6m Я собираю в Visual Studio 2017 c ++ 14 .

1 Ответ

1 голос
/ 06 апреля 2020

Если вы не хотите предоставить перегрузку, которая может выиграть разрешение перегрузки, с помощью ссылки переадресации (то есть параметра lvalue Type&), вы можете исключить нежелательную функцию из рассмотрения через SFINAE:

#include <boost/type_traits.hpp>

template <class Type>
class GetValue : public boost::static_visitor<Type>
{
public:
    template <class Other>
    auto operator()(Other&& o) const
        -> typename boost::disable_if<boost::is_same<typename boost::decay<Other>::type, Type>, Type>::type
    {
        throw error("Nope.");
    }
    Type operator()(const Type& t) const
    {
        return t;
    }
};

DEMO

...