lundi 25 juillet 2016

How to pass template template parameter to template class without the underlying template parameter?

Take, for example, the following code:

#include <iostream>
#include <string>
#include <unordered_map>


class Foo
{
    public:
        Foo()
        {
        }
        Foo(const std::string& baz)
            : baz_(baz)
        {
        }
        virtual ~Foo()
        {
        }

        const std::string& baz() const
        {
            return this->baz_;
        }

    private:
        std::string baz_;
};

template<class TFoo>
struct Bar
{
    typedef TFoo foo_t;
    typedef TFoo (*get_foo_f_t)(const char*);
    typedef std::unordered_map<int, get_foo_f_t> foo_handler_map_t;

    Bar(const foo_handler_map_t& handlers)
        : handlers_(handlers)
    {
    }
    ~Bar()
    {
    }

    const foo_handler_map_t& handlers_;
};

template<class TFoo, const Bar<TFoo>& CBar>
class Quux
{
    public:
        Quux()
            : bar_(CBar)
        {
        }
        ~Quux()
        {
        }

        TFoo action(int a, const char* x)
        {
            auto it = this->bar_.handlers_.find(a);
            if (it == this->bar_.handlers_.end())
            {
                return TFoo();
            }
            return it->second(x);
        }

    private:
        const Bar<TFoo>& bar_;
};


Foo _hdl_0(const char* x)
{
    return Foo(std::string("HDL #0 ") + x);
}

Foo _hdl_1(const char* x)
{
    return Foo(std::string("HDL #1 ") + x);
}

Foo _hdl_2(const char* x)
{
    return Foo(std::string("HDL #2 ") + x);
}


static std::unordered_map<int, Foo (*)(const char*)> handlers
{
    { 0, _hdl_0 },
    { 1, _hdl_1 },
    { 2, _hdl_2 }
};

const Bar<Foo> bar (handlers);


int main()
{
    Quux<decltype(bar)::foo_t, bar> quux;

    std::cout << quux.action(0, "abc").baz() << std::endl;
    std::cout << quux.action(1, "def").baz() << std::endl;
    std::cout << quux.action(2, "ghi").baz() << std::endl;
    std::cout << std::endl;
    std::cout << quux.action(2, "abc").baz() << std::endl;
    std::cout << quux.action(0, "def").baz() << std::endl;
    std::cout << quux.action(1, "ghi").baz() << std::endl;
    std::cout << std::endl;
    std::cout << quux.action(1, "abc").baz() << std::endl;
    std::cout << quux.action(2, "def").baz() << std::endl;
    std::cout << quux.action(0, "ghi").baz() << std::endl;

    return 0;
}

Notice that the 'Quux' class takes two template parameters - one that is also a template parameter for the 'Bar' class, and the template 'Bar' class itself. I would like to be able to do the following instead:

Quux<bar> quux;

Note: 'bar' is an object of type Bar<Foo>, but it should also be able to be any Bar<T> type.

Is this possible? I was thinking that maybe something like below could be used as a quick workaround, but I can't figure out what to put in place of /* ??? */:

template<const Bar</* ??? */>& CBar>
using Nuff = Quux<decltype(CBar)::foo_t, CBar>

Nuff<bar> nuff;

Aucun commentaire:

Enregistrer un commentaire