Невозможно определить тип элемента шаблонного класса

Вдохновленный этим примером, а именно этим конкретным фрагментом кода

// ...
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
// ...
std::visit(overloaded {
    [](auto arg) { std::cout << arg << ' '; },
    [](double arg) { std::cout << std::fixed << arg << ' '; },
    [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
}, v);

... Я попытался определить член класса типа overloaded, но наткнулся на трудности, которые, как я считаю (но не совсем уверен), были вызваны неспособностью компилятора определить параметры шаблона.

template<class ...Ts>
struct overloaded : Ts... {
    using Ts::operator()...;
    constexpr overloaded(Ts... ts) : Ts(ts)... {}
};

struct as{};

class phil_t {
    int i;
    overloaded o { [&](as&) {cout << i << "as"; } }; // <-- HERE
};

Вот результат, который я получаю:

../../variant.hpp:21:5: error: invalid use of template-name ‘overloaded’ without an argument list
     overloaded o { [&](as&) {cout << i << "as"; } };
     ^~~~~~~~~~

Что характерно, когда я использую тот же подход для создания экземпляра объекта не внутри класса, все работает просто гладко.

void varnt() {
    int i = 42;
    auto o = overloaded( [&](as&) {cout << i << "as"; } );
}

Мы будем чрезвычайно признательны за любые советы, объяснения или намеки на обходные пути.

Спасибо.


person Dmitry Murashov    schedule 07.01.2020    source источник
comment
@Evg Не совсем так. Это помогло мне понять, почему, а не как. Но все равно спасибо :)   -  person Dmitry Murashov    schedule 07.01.2020
comment
Кажется, что нет простого способа разорвать циклические зависимости. Одно из возможных решений - использовать стирание типа. Насколько это практично, я не уверен.   -  person Evg    schedule 07.01.2020


Ответы (1)


У вас не может быть переменной-члена, которая не относится к определенному типу, что вы пытаетесь сделать в phil_t, поскольку overloaded относится к шаблону, а не к типу.

class phil_t;

auto make_overloaded(phil_t& pt) {
    return  overloaded { [&](auto & x) { /* do something with x */ } };
}

class phil_t {
    int i;
    decltype(make_overloaded(std::declval<phil_t&>())) o = make_overloaded(*this);  // <-- HERE
};

Живой пример здесь.

Проблема с этим кодом заключается в том, что вы хотите использовать phil_t в своей лямбде, поэтому вы не можете использовать мой подход, потому что phil_t является неполным при вызове make_overload.

Спасибо @Evg: вот решение, использующее стирание типа, которое работает лучше, чем приведенный выше код:

#include <iostream>
#include <any>

template<class ...Ts>
struct overloaded : Ts... {
    using Ts::operator()...;
    constexpr overloaded(Ts... ts) : Ts(ts)... {}
};

struct as1 {};
struct as2 {};

class phil_t {
private:
    auto make_overloaded() {
        return overloaded{
            [&](as1& x) { std::cout << "1: " << i << std::endl; },
            [&](as2& x) { std::cout << "2: " << i << std::endl; }
        };
    }

public:
    phil_t() : o(make_overloaded()) {}

    template<class As>
    void foo(As as) {
        std::any_cast<decltype(make_overloaded())>(o)(as);
    }

private:
    int i = 42;
    std::any o;
};

int main() {
    phil_t p;
    p.foo(as1{});
    p.foo(as2{});
}

Все кредиты этого второго фрагмента относятся к @Evg!

Живой пример здесь.

person florestan    schedule 07.01.2020
comment
Обратите внимание на [&] и i в лямбде OP. - person Evg; 07.01.2020
comment
@Evg ах, верно, спасибо. - person florestan; 07.01.2020
comment
Если вы попытаетесь использовать pt в лямбде, вы получите ошибку неполного типа. - person Evg; 07.01.2020
comment
правильно, только что разобрался ... - person florestan; 07.01.2020
comment
Я думаю, это проблема курицы и яйца. Есть идеи, как это исправить? - person florestan; 07.01.2020
comment
Большое спасибо, ваш ответ дал мне несколько идей. Я попробую придумать решение. - person Dmitry Murashov; 07.01.2020
comment
Стирание типа, возможно: godbolt.org/z/XUqIMO - person Evg; 07.01.2020
comment
@Evg: Мило! Вы должны ответить на него, тогда я могу удалить свой пост ... - person florestan; 07.01.2020
comment
Вопрос закрыт, поэтому не могу. Но вы можете скопировать это в свой ответ, если считаете, что это возможно. - person Evg; 07.01.2020
comment
@Evg Спасибо вам обоим. Это решение соответствует моим потребностям больше, чем я мог бы пожелать. Спасибо! - person Dmitry Murashov; 07.01.2020