简体   繁体   中英

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

Take, for example, the following code:

// Say I have this class defined in some other file
class Foo;

// This class will act as a wrapper for an integer map
// to function pointers, which will create type TFoo objects
// depending on the given input (in this case a "const char*"
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_;
};

// Now, this class will receive an _object_ of type
// "const Bar<T>&", which will have an already initialized
// map of integers to function pointers, different
// functions will be called with different input values
// via the public method, "action()".
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())
            {
                // no handler defined for int `a'
                return TFoo();
            }
            // i.e. CBar.handlers_[a](x)
            return it->second(x);
        }

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


// Here is how the map of integers to function pointers
// will be initialized...
static std::unordered_map<int, Foo (*)(const char*)> handlers
{
    { 0, _hdl_0 }, // _hdl_* functions defined in different file
    { 1, _hdl_1 },
    { 2, _hdl_2 }
};
// And then passed to a "const Bar<T>" type object here
const Bar<Foo> bar (handlers);


int main()
{
    // --> HERE IS WHAT I WANT TO CHANGE <--
    Quux<decltype(bar)::foo_t, bar> quux;
    // -------------------------------------

    // Example (trivial) use of the 'quux' object
    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;

    return 0;
}

Notice that the 'Quux' class takes two template parameters - one that is also a template parameter for the 'Bar' class, and a reference to a template object of type const Bar<T> , where T is any class related to 'Foo'. I would like to be able to do the following instead:

Quux<bar> quux;

'bar' is an object of type Bar<Foo> , but it should also be able to be any Bar<T> type. 'bar'是Bar<Foo>类型的对象,但它也应该可以是任何Bar<T>类型。

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;




I'm passing in a reference to an object to 'Quux' as a template parameter because copying would be inefficient (I think), rather than making a copy of the entire foo_handler_map_t object. I just want to be able to have a bunch of objects of type const Bar<T> that are defined globally in some namespace, and to be able to initialize 'Quux' objects like so:

namespace blah
{
std::unordered_map<int, /* funcptr type 0 */> _funcmap_0 { ... }
std::unordered_map<int, /* funcptr type 1 */> _funcmap_1 { ... }
...

const Bar<Foo0> FSET0 (_funcmap_0);
const Bar<Foo1> FSET1 (_funcmap_1);
...
}

int main()
{
    Quux<blah::FSET0> a;
    Quux<blah::FSET1> b;

    ...

    return 0;
}

...And I do NOT want to pass it as a constructor argument.

The comments are very useful. However, if you wish to reduce the number of template arguments, you can pass the CBar as an argument to the constructor:

template<class TFoo>
class Quux
{
public:
    Quux(const Bar<TFoo>& CBar)
        : 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_;
};

And define a function to create an instance of Quux :

template <typename TFoo>
auto make_Quux(const Bar<TFoo>& bar)
{
    return Quux<TFoo>(bar);
}

Then in main() , you can use make_Quux() :

int main()
{
    auto quux = make_Quux(bar);
    //...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM