Условные определения типов - PullRequest
6 голосов
/ 28 февраля 2010

Если у меня есть маленький кусочек кода как таковой ...

template <typename _T>
class Foo
{
public:
    typedef const T& ParamType;
    void DoStuff(ParamType thingy);
};

Это может быть неоптимально, если sizeof(_T) <= sizeof(_T*).

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

Ответы [ 5 ]

5 голосов
/ 28 февраля 2010

Довольно легко добиться с помощью частичной специализации шаблона .

template< typename _T, bool _ByVal >
struct FooBase {
  typedef const _T& ParamType;
};

template< typename _T >
struct FooBase< _T, true > {
  typedef const _T ParamType;
};

template< typename _T, bool _ByVal = sizeof(_T) <= sizeof(void*) >
class Foo : public FooBase< _T, _ByVal > {
  typedef typename FooBase< _T, _ByVal >::ParamType ParamType;
  void DoStuff(ParamType thingy);
};

РЕДАКТИРОВАТЬ Согласно решению Джеффа, действительно нужно сравнивать sizeof(_T) и sizeof(_T&), но я сохранил первоначальное требование <= void*.

4 голосов
/ 28 февраля 2010
template <class T, bool Smaller>
class BestArgumentPassingType {};

template <class T>
class BestArgumentPassingType<T, true> {
  public:
    typedef T Type;
};

template <class T>
class BestArgumentPassingType<T, false> {
  public:
    typedef const T& Type;
};

template <class T>
class ArgumentType : public BestArgumentPassingType<T, sizeof(T) < sizeof(T*)> {
};

struct B { double d; double d2; };
struct S { double d; };

class A {
  public:
    static void foo(ArgumentType<B>::Type big);
    static void bar(ArgumentType<S>::Type small);
};

int main()
{
  B b;
  S s;
  A::foo(b);
  A::bar(s);
  return 0;
}

Вот так.

4 голосов
/ 28 февраля 2010

Вы можете сделать это, но это немного сложно.

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

В качестве конкретного примера, размер std::vector на самом деле очень мал, поскольку он выделяет всю память в куче и нуждается только в указателе. Однако копирование вектора занимает гораздо больше времени. Нечто подобное нельзя включить в условие.

Лучше всего здесь пройти мимо const &, чтобы охватить наихудший случай. Кроме того, я не могу этого гарантировать, но я считаю, что компилятор был бы достаточно умен, чтобы передавать по значению, если бы считал, что это более эффективно.

3 голосов
/ 28 февраля 2010

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

template<typename>
struct tovoid { typedef void type; };

template<typename T, typename = void>
struct parm_type {
  typedef T type;
};

template<typename T>
struct parm_type<T, typename tovoid<int T::*>::type> {
  typedef T const& type;
};

template <typename T>
class Foo
{
public:
    typedef typename parm_type<T>::type ParamType;
    void DoStuff(ParamType thingy);
};

Это реализует (на мой взгляд) очень хорошую мысль, которую высказал @Poita_.

3 голосов
/ 28 февраля 2010

Вы можете использовать Усилить характеристики вызова .

template <typename _T>
class Foo
{
public:
    void DoStuff(boost::call_traits<_T>::param_type thingy);
};

Из документации:

Если T - маленький встроенный тип или указатель,тогда param_type определяется как T const, а не T const &.

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