Проблема специализации шаблонов C ++ - PullRequest
3 голосов
/ 26 мая 2009

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

template <typename T, T &N>
struct C {
    enum { Value = 0 };
};

template <int &N>
struct C<int, N> {
    enum { Value = N };
};

но это не работает. Есть ли способ добиться чего-то подобного?

Редактировать

То, чего я пытался добиться, было что-то вроде этого, что случилось бы во время компиляции:

if (type is int) {
    return IntWrapper<int_value>
else {
    return type
}

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

struct X {
    static const int Value = 5;
};

template <X *x>
struct C {
    static const int Value = (*x).Value; 
};

X x;

std::cout << C<&x>::Value << std::endl; // prints 5

но, очевидно, все это завершается инициализацией шаблона, выводя тип x, и x также необходимо объявить глобально. Бесполезно то, что я пытаюсь сделать, что, по-моему, невозможно во время компиляции.

Ответы [ 11 ]

7 голосов
/ 26 мая 2009

То, что вы пытаетесь сделать, не соответствует шаблонам C ++. Вы не можете использовать произвольные объекты в качестве параметров шаблона, все, что вы можете использовать, это типы, целочисленные литералы и в некоторых особых случаях строковые литералы.

5 голосов
/ 26 мая 2009

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

template <X *x>
struct C {
    static const int Value = (*x).Value; 
};

Это недопустимо, поскольку (*x).Value должно быть константным выражением, чтобы иметь возможность инициализировать Value. Конечно, Value в пределах класса X будет хорошо в качестве константного выражения, если вместо этого использовать X::Value. Но на этот раз это не так, поскольку в нем используется указатель (ссылки одинаково недопустимы в константных выражениях).

Подводя итог, вы не можете сделать это:

Magic<T, someT>::type

И ожидайте, что ::type будет T, если T не int, и IntWrapper<someT> в противном случае, поскольку T может быть только перечислением, целым числом, указателем или ссылочным типом. И в последних двух случаях вы не получите «значение» чего-либо, на что указывает указатель или на которое указывает ссылка в время компиляции . Если вы удовлетворены этим, то решить вашу проблему легко, и я не собираюсь показывать вам, как (я подозреваю, вы уже знаете, как).

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

4 голосов
/ 26 мая 2009

Возможно, в вашем случае работает простой перегруженный шаблонный метод?

template<typename T>
void doSomething(const T& x)
{
    // ...
}
void doSomething(int x)
{
    // ...
}
3 голосов
/ 26 мая 2009

Добавление к другим сообщениям: вам больше не нужно использовать enum {} -хак:

template<typename T, int val>
struct Test {
    static const int Value = 0;
};

template <int val>
struct Test<int, val> {
    static const int Value = val;
};


int main(int argc,char *argv[]) {
    const int v = Test<int,1>::Value;
}
3 голосов
/ 26 мая 2009

template <typename T> struct A
{
    enum { Value = false };
};
template <> struct A<int>
{
    enum { Value = true };
};

Как насчет этого:


template <typename T> struct A
{
    T value_;
    A() : value() {}
    enum { is_int = false };
};
template <> struct A<int>
{
    int value_;
    explicit A( int v ) : value_( v ) {}
    enum { is_int = true };
};
2 голосов
/ 26 мая 2009

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

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

Обратите внимание, что во всех ответах ваш оригинальный шаблон был аккуратно изменен на

template < typename T, int >
class C {};

вместо вашего

template< typename T, T >
class C {};

Но, хотя C<int, 5> является совершенно допустимым объявлением, это не относится к произвольному типу T, в данном случае C<float, 5.> приведет к ошибке компилятора.

Можете ли вы опубликовать то, что вы пытаетесь достичь в точности?

И для записи, если вторым аргументом шаблона всегда является int, и вы просто хотите принять его значение, если тип является целочисленным типом, и 0 в противном случае, вы можете просто сделать:

#include <limits>

template< typename T, int N >
class C {
    static const int Value = (std::numeric_limits<T>::is_integer) ? N : 0;
};
2 голосов
/ 26 мая 2009

Вы можете сделать это так:

template<typename T, int val>
struct Test
{
    enum {Value = 0};
};

template <int val>
struct Test<int, val>
{
    enum {Value = val};
};




int main(int argc,char *argv[])
{
    int v = Test<int,1>::Value;
}  
0 голосов
/ 09 сентября 2009

То, чего я пытался достичь, было примерно так, что могло бы произойти во время компиляции:

if (type is int) {
    return IntWrapper<int_value>
else {
    return type
}

Я не уверен, почему вы не используете IntWrapper для начала. Откуда возникает необходимость обернуть целочисленную константу времени компиляции в IntWrapper, если это int?

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

0 голосов
/ 09 сентября 2009

Специализация шаблона может быть достигнута следующим образом (код взят с www.cplusplus.com):

// template specialization
#include <iostream>
using namespace std;

// class template:
template <class T>
class mycontainer {
    T element;
  public:
    mycontainer (T arg) {element=arg;}
    T increase () {return ++element;}
};

// class template specialization:
template <>
class mycontainer <char> {
    char element;
  public:
    mycontainer (char arg) {element=arg;}
    char uppercase ()
    {
      if ((element>='a')&&(element<='z'))
      element+='A'-'a';
      return element;
    }
};

int main () {
  mycontainer<int> myint (7);
  mycontainer<char> mychar ('j');
  cout << myint.increase() << endl;
  cout << mychar.uppercase() << endl;
  return 0;
}

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

0 голосов
/ 26 мая 2009

Проверьте Александреску Современный дизайн C ++ . Я считаю, что в главе 2 есть правильный пример того, что вы хотите сделать.

...