C ++: как использовать шаблон на классах и примитивах? - PullRequest
5 голосов
/ 04 июня 2011

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

(Примечание: у меня есть более сложный реальный код, следующий код бесполезен, но воспроизводит ту же проблему)

template<typename T>
class Foo
{
  T value;

public:
  Foo() {}
  const T& getValue() const { return value; }
  Foo& setValue(const T& other) { 
    value = other; return *this; 
  }
};

struct Bar
{
  int x;

  Bar() : x(3) {}
};

int doit()
{
  Foo<int> fooint;
  Bar bar;
  bar.x = 44;
  Foo<Bar> foobar;

  fooint.setValue(3);      // warning here
  foobar.setValue(bar);

  int y = foobar.getValue().x + fooint.getValue();
  return y;
}

Я получаю замечание компилятора о fooint.setValue():

value copied to temporary, reference to temporary used

Я понимаю замечание. Что меня интересует, так это то, как мне следует обрабатывать Foo::setValue(), если я собираюсь использовать Foo как с примитивами, так и с типами классов / структур в качестве параметров шаблона.

Я думал, setValue(const T& other) была правильной сигнатурой метода для передачи константного класса по ссылке.

Есть ли способ сделать setValue (), чтобы он "правильно делал" как для Foo<int>, так и для Foo<Bar>?

Ответы [ 4 ]

8 голосов
/ 04 июня 2011

Совершенно законно привязывать временные ссылки к константным ссылкам, как вы делаете в setValue(). Intel C ++, которая выдает это замечание, в этом случае не помогает.

РЕДАКТИРОВАТЬ: я предполагаю, что TI-компилятор основан на Intel, которая для меня выдает следующую диагностику в этой строке:

test.cc(28): remark #383: value copied to temporary, reference to temporary used
    fooint.setValue(3);      // warning here

Диагностика обсуждается на http://software.intel.com/en-us/articles/cdiag383/, где написано

Может смело игнорировать это предупреждение для функции обратного хода вектора. Вектор копирует аргумент в свое собственное хранилище; он никогда не хранит исходный аргумент. Поэтому использование временного совершенно безопасно.

В вашем случае вы также копируете аргумент, поэтому его также можно игнорировать.

1 голос
/ 04 июня 2011

Чтобы ответить на ваш последний вопрос о том, как заставить Foo<T>::setValue() сделать «правильную вещь», вы можете использовать для этого специализацию шаблонов - довольно распространенный метод, используемый в метапрограммировании шаблонов.Примерно так, например:

template <typename T>
struct Ref_or_Value
{
    typedef T& type;
};

template <typename T>
struct Ref_or_Value<T *>
{
    typedef T* type;
};

template <>
struct Ref_or_Value<int>
{
    typedef int type;
};

// add other primitive types like above as need

. Подпись Foo<T>::setValue становится:

Foo& setValue(const typename Ref_or_Value<T>::type other);

. Будет ли это излишним или нет, я дам вам решение, но для него должно быть установлено значениесделать правильную вещь'.Если T=int, тогда setValue будет принимать аргументы по значению.Если T=Foobar_object, то это будет по константной ссылке.

1 голос
/ 04 июня 2011

Я не вижу ничего плохого в вашем коде. GCC компилирует его без ошибок и предупреждений.

0 голосов
/ 04 июня 2011

В Visual Studio 2010 для меня не выдается никакого предупреждения / ошибки / чего бы то ни было. Очень странно, что ваш компилятор показывает эту диагностику, поскольку она не имеет смысла. 3 является rvalue, и rvalue явно разрешено привязывать к константным ссылкам, таким как const int&.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...