条件typedef

时间:2010-02-28 00:44:35

标签: c++ templates

如果我有一点点代码......

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

如果sizeof(_T) <= sizeof(_T*),这可能不是最佳的。

因此,我希望有条件typedef。如果_T的大小小于或等于指针的大小,则只需将其传递给值。否则,通过const引用传递它。这可能吗?我听到所有这些关于模板完成图案的东西,但这让我头疼。

5 个答案:

答案 0 :(得分:5)

使用partial template specialization非常容易实现。

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*要求。

答案 1 :(得分:4)

你可以这样做,但这有点棘手。

我的主要关注点如果你的动机。我知道你不想按值传递大对象,但是对象是否大是无关紧要的 - 你真正想知道的是复制构造函数创建参数需要多长时间

作为一个具体的例子,std::vector的大小实际上非常小,因为它分配堆上的所有内存并且只需要一个指针。但是,复制矢量需要更多时间。这样的事情不是你可以真正包含在条件中的东西。

这里最好的选择就是通过const &以便覆盖最糟糕的情况。此外,我无法保证这一点,但我相信如果编译器认为更高效,那么编译器就足够聪明,可以通过值传递。

答案 2 :(得分:4)

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;
}

喜欢这样。

答案 3 :(得分:3)

您可以使用Boost call traits

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

来自文档:

  

如果T是小型内置类型或指针,则param_type定义为T const,而不是T const&amp ;.

答案 4 :(得分:3)

我知道这不是你所要求的,但这是你的目标。我会用另一种方法来实现这一点:通过引用传递类(包括结构和联合),并按值传递其他所有内容。

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_做的非常好的观点。