2013-11-12 2 views
7

Как я могу иметь несколько аргументов typename в шаблоне C++?Несколько аргументов имени типа в шаблоне C++?

#ifndef _CALL_TEMP_H 
#define _CALL_TEMP_H 

#include <string> 
#include <iostream> 

template <typename Sig> 
class Foo; 

template <typename A, typename B> 
class Foo 
{ 
    public: 
     void output() { 
      std::cout << a_ << b_ << std::endl; 
     } 
     A a_; 
     B b_; 
}; 

template <typename A, typename B, typename C> 
class Foo 
{ 
    public: 
     void output() { 
      std::cout << a_ << b_ << c_ << std::endl; 
     } 
     A a_; 
     B b_; 
     C c_; 
}; 

#endif 

Использование:

int main() 
{ 
    Foo<int ,int> doubleint; 
    doubleint.a_ = 1; 
    doubleint.b_ = 2; 
    doubleint.output(); 
// Foo<int , int , std::string> comp; 
// comp.a_ = 1; 
// comp.b_ = 2; 
// comp.c_ = "haha"; 
// comp.output(); 
    return 0; 
} 

Но это не будет компилироваться. Как я могу скомпилировать его?

ответ

23

Просто объявите первичный шаблон с вариационным шаблоном, а затем специализируйтесь на каждом поддерживаемом числе аргументов шаблона. Например:

#ifndef CALL_TEMP_H 
#define CALL_TEMP_H 

#include <iostream> 

template <typename...> class Foo; 

template <typename A, typename B> 
class Foo<A, B> 
{ 
public: 
    void output() { 
     std::cout << a_ << b_ << '\n'; 
    } 
    A a_; 
    B b_; 
}; 

template <typename A, typename B, typename C> 
class Foo<A, B, C> 
{ 
public: 
    void output() { 
     std::cout << a_ << b_ << c_ << '\n'; 
    } 
    A a_; 
    B b_; 
    C c_; 
}; 

#endif 

Я не могу использовать C++ 11 и вы хотите сохранить подобную нотацию вам нужно, чтобы имитировать VARIADIC список аргументов с аргументами шаблона по умолчанию. Это косвенно ограничит количество аргументов templare, но поскольку вы все равно специализируетесь на шаблонах, это ограничение не имеет особого значения.

Если это приемлемо использовать различные обозначения можно также использовать то, что выглядит как объявление функции для создания экземпляра и специализации шаблона:

template <typename> class Foo; 

template <typename A, typename B> 
class Foo<void(A, B)> { 
    ... 
}; 
template <typename A, typename B, typename C> 
class Foo<void(A, B, C)> { 
    ... 
}; 
... 
Foo<void(int, int)>     f2; 
Foo<void(int, int, std::string)> f3; 

ли изменение в обозначении является приемлемым, зависит от использования шаблон шаблона. Тем не менее, вы не достигнете идеального решения, как с вариативными шаблонами без C++ 11.

BTW, don't overuse std::endl: использовать '\n' для обозначения конца строки. Если вы действительно хотите смыть поток, используйте std::flush. Также _CALL_TEMP_H - это имя, зарезервированное для стандартной библиотеки C++, как и все имена, начинающиеся с символа подчеркивания, за которым следует символ капитала: не используют эти имена в своем собственном коде, если только у них нет явного разрешения на их использование (например, и __LINE__ являются зарезервировано, но явное разрешение на их использование предоставляется).

+0

+1 Это сделало мой ответ шуткой! – deepmax

+0

+1 но в окнах только визуальная студия 2013 поддерживает аргумент шаблона varadic, поэтому я бы предпочел C++ 98. – Jichao

+0

@Jichao: В окнах у вас есть MinGW/GCC, который идеально подходит. – deepmax

0

Вы не можете. Вы объявляете Foo в двух форматах. Один с 2-мя аргументами шаблона, а другой с 3.

Try специализации:

template <typename A, typename B, typename C = void> 
class Foo; 

template <typename A, typename B> 
class Foo<A, B, void> 
{ 
}; 

template <typename A, typename B, typename C> 
class Foo 
{ 
}; 
0

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

1

Если у вас несколько версий шаблона, вам необходимо специализироваться на одной версии. Если вы хотите различное количество аргументов, то трюк заключается в том, чтобы использовать класс тега, чтобы сказать, что «этот аргумент не является аргументом» и имеет это как аргумент по умолчанию.

В вашем случае, что-то вроде следующих работ (составитель и тестировался):

#include <iostream> 

// tag class indicating "no member in this place" 
struct nothing {}; 

template <typename A, typename B, typename C = nothing> // <- note default arg. 
class Foo; 

template <typename A, typename B> 
class Foo<A, B, nothing> // <- note specialization 
{ 
    public : 
     void output() { 
      std::cout << a_ << b_ << std::endl; 
     } 

     A a_; 
     B b_; 
}; 

template <typename A, typename B, typename C> 
class Foo 
{ 
    public : 
     void output() { 
      std::cout << a_ << b_ << c_ << std::endl; 
     } 

     A a_; 
     B b_; 
     C c_; 
}; 

int main() 
{ 
    Foo<int, int> doubleint; 
    doubleint.a_ = 1; 
    doubleint.b_ = 2; 
    doubleint.output(); 

    Foo<int, int, int> tripleint; 
    tripleint.a_ = 1; 
    tripleint.b_ = 2; 
    tripleint.c_ = 3; 
    tripleint.output(); 
} 

Обратите внимание, что это, по существу повторно изобретение наддува :: кортеж <>/станд :: кортеж <> которые вы обязательно должны прочитать.

+1

Также обратите внимание, что это ответ на C++ 98, в то время как ответ Dietmar (совершенно прекрасный) - это ответ C++ 11. –

0

Он не будет компилироваться, потому что вы не можете иметь один и тот же класс, определенный несколько раз, с различным числом аргументов шаблона.

Если вы знаете, максимальное количество параметров шаблона, который вы хотите поддержать, вы могли бы использовать частичную специализацию:

// main template 
template <typename A, typename B = void, typename C = void> 
struct Foo 
{ 
    void output() { std::cout << a_ << b_ << c_ << std::endl; } 
    A a_; 
    B b_; 
    C c_; 
}; 

// Partial specialisation for two parameters 
template <typename A, typename B> 
struct Foo<A, B, void> 
{ 
    void output() { std::cout << a_ << b_ << c_ << std::endl; } 
    A a_; 
    B B_; 
}; 

// Partial specialisation for one parameter 
template <typename A> 
struct Foo<A, void, void> 
{ 
    void output() { std::cout << a_ << std::endl; } 
    A a_; 
}; 

Если вы используете C++ 11, другой вариант будет использовать VARIADIC шаблоны.

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