Если у меня есть немного части o' код как таковой...
template <typename _T>
class Foo
{
public:
typedef const T& ParamType;
void DoStuff(ParamType thingy);
};
Это может быть неоптимально если sizeof(_T) <= sizeof(_T*)
.
Поэтому я хочу иметь условное выражение typedef
. Если размер _T
меньше чем или равно тому из указателя, просто передайте его в значением. Иначе передайте его ссылкой константы. Действительно ли это возможно? Я слышу весь этот материал о шаблонах, являющихся завершенным Тьюрингом, но это повреждает мою голову.
Довольно легко добиться с помощью частичная специализация шаблона .
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 *
требование.
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;
}
Вроде так.
Вы можете использовать черты вызова Boost .
template <typename _T>
class Foo
{
public:
void DoStuff(boost::call_traits<_T>::param_type thingy);
};
Из документации:
Если T - небольшой встроенный тип или указатель, тогда param_type определяется как T const, а не T const &.
Я знаю, что это не совсем то, о чем вы просили, но это ваша цель. Я бы использовал другой способ добиться этого: передавать классы (включая структуры и объединения) по ссылке, а все остальное передавать по значению.
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_.
Вы можете это сделать, но это немного сложно.
Меня больше всего беспокоит ваш мотив. Я понимаю, что вы не хотите передавать большие объекты по значению, но независимо от того, большой объект или нет, не имеет значения - вы действительно хотите знать , сколько времени потребуется конструктору копирования для создания параметра .
В качестве конкретного примера, размер std :: vector
на самом деле очень мал, поскольку он выделяет всю память в куче, и ему нужен только указатель. Однако копирование вектора занимает гораздо больше времени. Нечто подобное нельзя включить в условие.
Лучше всего просто пройти мимо const &
, чтобы охватить худший случай. Кроме того, я не могу этого гарантировать, но я считаю, что компилятор был бы достаточно умен, чтобы передавать по значению, если бы считал, что это более эффективно.