Условные определения типов

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

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

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

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

6
задан Joseph Mansfield 23 January 2013 в 12:41
поделиться

5 ответов

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

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 * требование.

5
ответ дан 8 December 2019 в 12:19
поделиться
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
ответ дан 8 December 2019 в 12:19
поделиться

Вы можете использовать черты вызова Boost .

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

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

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

3
ответ дан 8 December 2019 в 12:19
поделиться

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

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
ответ дан 8 December 2019 в 12:19
поделиться

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

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

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

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

4
ответ дан 8 December 2019 в 12:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: