一个模板专门用于多个类

发布于 2024-08-24 19:45:16 字数 359 浏览 9 评论 0原文

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

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

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

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

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

Let's assume we have a template function "foo":

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

I can make specialization for some particular type, e.g.

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

If I wanted to use the same specialization for all builtin numeric types (int, float, double etc.) I would write those lines many times. I know that body can be thrown out to another function and just call of this is to be made in every specialization's body, however it would be nicer if i could avoid writting this "void foo(..." for every type. Is there any possibility to tell the compiler that I want to use this specialization for all this types?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

无声无音无过去 2024-08-31 19:45:16

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

// 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>()); }

You could use std::numeric_limits to see whether a type is a numeric type (is_specialized is true for all float and integer fundamental types).

// 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>()); }
喜爱纠缠 2024-08-31 19:45:16

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

foo.inc:

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

foo.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

You can use an approach with preprocessor.

foo.inc:

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

foo.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

etc.

浅浅淡淡 2024-08-31 19:45:16

使用 boost:

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

您可以在不使用 boost 的情况下轻松完成:

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

With boost:

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

You can mostly easily do it without boost:

#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);
}
¢蛋碎的人ぎ生 2024-08-31 19:45:16

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

maybe you can define a default template function that will work on all native type, and delegate specialization of custom type to user

鹿港小镇 2024-08-31 19:45:16

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

注意:这假设 foo 的实现对于每种类型都可以变得简单且相似,例如,只需调用真正的实现函数。但它避免了一堆模板/预处理器的胡言乱语,这可能会让未来的维护者摸不着头脑。

You could write a small script (e.g., Perl) to generate the source file for you. Create an array containing all the types you want to specialize, and have it write out the function header for each. You can even embed the script execution in your makefile to automagically re-run it if you change something.

Note: this assumes the implementation of foo can be made trivial and similar for each type, e.g., simply calling out to the real implementation function. But it avoids a bunch of template/preprocessor mumbo-jumbo that might make a future maintainer scratch his head.

短叹 2024-08-31 19:45:16

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

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

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

Here's a refinement of Johannes solution, but easier to read. Just do the type check inside the function:

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

Using type traits (which itself is template specialization) allows replacing a bunch of template specializations with a single, easy to read function template

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文