14

假设我们有一个模板函数“foo”:

template<class T>
void foo(T arg)
{ ... }

我可以对某些特定类型进行专业化,例如

template<>
void foo(int arg)
{ ... }

如果我想对所有内置数字类型(int、float、double 等)使用相同的特化,我会多次编写这些行。我知道 body 可以被扔到另一个函数中,只需在每个专业化的 body 中调用它,但是如果我可以避免为每种类型写这个“void foo(...”)会更好。有没有有没有可能告诉编译器我想对所有这些类型使用这个专业化?

4

6 回答 6

19

您可以使用std::numeric_limits来查看类型是否为数字类型(is_specialized对于所有浮点和整数基本类型都为真)。

// small utility
template<bool> struct bool2type { };

// numeric
template<typename T>
void fooImpl(T arg, bool2type<true>) {

}

// not numeric
template<typename T>
void fooImpl(T arg, bool2type<false>) {

}

template<class T>
void foo(T arg)
{ fooImpl(arg, bool2type<std::numeric_limits<T>::is_specialized>()); }
于 2010-03-12T02:19:40.500 回答
3

您可以使用带有预处理器的方法。

foo.inc:

template<>
void foo(TYPE arg)
{ /* do something for int, double, etc. */ }

富.h:

template<class T>
void foo(T arg)
{ /*do something */ }

#define TYPE int
#include "foo.inc"
#undef TYPE

#define TYPE double
#include "foo.inc"
#undef TYPE

等等

于 2010-03-12T02:20:53.817 回答
3

带升压:

#include <boost/type_traits/is_scalar.hpp>
#include <iostream>
#include <string>

namespace detail
{
    typedef const boost::true_type& true_tag;
    typedef const boost::false_type& false_tag;

    template <typename T>
    void foo(const T& pX, true_tag)
    {
        std::cout << "special: " << pX << std::endl;
    }

    template <typename T>
    void foo(const T& pX, false_tag)
    {
        std::cout << "generic: " << pX << std::endl;
    }
}

template <typename T>
void foo(const T& pX)
{
    detail::foo(pX, boost::is_scalar<T>());
}

int main()
{
    std::string s = ":D";
    foo(s);
    foo(5);
}

你可以很容易地做到这一点,而无需提升:

#include <iostream>
#include <string>

// boolean stuff
template <bool B>
struct bool_type {};

typedef bool_type<true> true_type;
typedef bool_type<false> false_type;

// trait stuff
template <typename T>
struct is_scalar : false_type
{
    static const bool value = false;
};

#define IS_SCALAR(x) template <> \
            struct is_scalar<x> : true_type \
            { \
                static const bool value = true; \
            };

IS_SCALAR(int)
IS_SCALAR(unsigned)
IS_SCALAR(float)
IS_SCALAR(double)
// and so on

namespace detail
{
    typedef const true_type& true_tag;
    typedef const false_type& false_tag;

    template <typename T>
    void foo(const T& pX, true_tag)
    {
        std::cout << "special: " << pX << std::endl;
    }

    template <typename T>
    void foo(const T& pX, false_tag)
    {
        std::cout << "generic: " << pX << std::endl;
    }
}

template <typename T>
void foo(const T& pX)
{
    detail::foo(pX, is_scalar<T>());
}

int main()
{
    std::string s = ":D";
    foo(s);
    foo(5);
}
于 2010-03-12T02:28:17.423 回答
0

也许您可以定义一个适用于所有本机类型的默认模板函数,并将自定义类型的专业化委托给用户

于 2010-03-12T02:10:14.440 回答
0

您可以编写一个小脚本(例如 Perl)来为您生成源文件。创建一个包含所有你想专门化的类型的数组,并让它写出每个类型的函数头。您甚至可以将脚本执行嵌入到您的 makefile 中,以便在您更改某些内容时自动重新运行它。

注意:这假设foo每个类型的实现都可以变得微不足道和相似,例如,简单地调用真正的实现函数。但它避免了一堆可能让未来的维护者摸不着头脑的模板/预处理器。

于 2010-03-12T02:28:51.230 回答
0

这是 Johannes 解决方案的改进版,但更易于阅读。只需在函数内部进行类型检查:

template<typename T>
void foo(T arg)
{
  if (numeric_limits<T>::is_specialized)  // not a runtime check - compile time constant
  {
  }
  else
  {
  }
}

使用类型特征(它本身就是模板特化)允许用一个易于阅读的函数模板替换一堆模板特化

于 2019-03-06T23:53:58.053 回答