2016-07-26 2 views
0

Возьмет, к примеру, следующий код:Как передать шаблон шаблона шаблону в класс шаблона без базового параметра шаблона?

// 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; 
} 

Обратите внимание, что класс в «Quux» принимает два параметра шаблона - один, который также является параметр шаблона для класса «Bar», и ссылка на шаблон объект типа const Bar<T>, где T - любой класс, относящийся к «Foo». Я хотел бы быть в состоянии сделать следующий вместо:

Quux<bar> quux; 

Примечания: «бар» является объектом типа Bar<Foo>, но он также должен быть в состоянии быть любым Bar<T> типа.

Возможно ли это? Я думал, что может быть что-то вроде ниже, могут быть использованы в качестве быстрого решения проблемы, но я не могу понять, что поставить вместо /* ??? */:

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

Nuff<bar> nuff; 


EDIT

Я передавая ссылку на объект в «Quux» в качестве параметра шаблона, потому что копирование будет неэффективным (я думаю), вместо того, чтобы делать копию всего объекта foo_handler_map_t. Я просто хочу, чтобы иметь возможность иметь кучу объектов типа const Bar<T>, которые определены глобально в некотором пространстве имен, и, чтобы иметь возможность инициализировать объекты «» Quux так:

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; 
} 

... И я не хотите передать его как аргумент конструктора.

+0

Что это 'шаблон <класс Тьфу, Const Bar & сантибар>' ? Поскольку вы указываете, что оно компилируется, я предполагаю, что оно действительно так же, как указатель на некоторый внешний объект. Но какова цель здесь, чего вы пытаетесь достичь? –

+2

Было бы неплохо, если бы вы смогли значительно сократить свой пример. Пожалуйста, предоставьте минимальный код, который нам нужен, чтобы уловить ваш вопрос! – Klaus

+2

Это невозможно в текущем C++, будет возможно сразу после [n4469] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4469.html). –

ответ

2

Замечания очень полезны. Тем не менее, если вы хотите, чтобы уменьшить количество аргументов шаблона, вы можете передать CBar в качестве аргумента конструктора:

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_; 
}; 

И определить функцию для создания экземпляра Quux:

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

Тогда в main(), вы можете использовать make_Quux():

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

Да, я не понимаю, почему кто-то использовал аргумент шаблона для ссылки, тем самым создавая совершенно другой тип для каждой ссылки, переданной в ... Однако ваш пример изменяет семантику класса. Вы должны, вероятно, отредактировать его, чтобы фактически отразить то, что делает OP, т. Е. Сохранить аргумент 1-го шаблона и все, что на нем нарисовано. Кроме того, обратите внимание, что в C++ 17 функции 'make_ *' станут ненужными, поскольку конструкторы смогут указать аргументы шаблона своих классов (как функции в настоящее время). –

Смежные вопросы