【问题标题】:More elegant solution on overloaded template classes重载模板类的更优雅的解决方案
【发布时间】:2012-10-25 18:04:15
【问题描述】:

我有 3 个课程,如下所示:

template <typename RET, typename ARG1 = int, [...], typename ARG5 = int>
class FunctionPointer {
    virtual operator()(ARG1, [...], ARG5);
};

template <typename RET, class TYPE, typename ARG1 = int, [...], typename ARG5 = int>
class ClassFunctionPointer : public FunctionPointer<RET, ARG1, [...], ARG5> {
    // make it so that class functions fit here
};

template <typename RET, typename ARG1 = int, [...], typename ARG5 = int>
class GlobalFunctionPointer : public FunctionPointer<RET, ARG1, [...], ARG5> {
    // make it so that non-member functions fit here
};

它们都是重载的,因此每个类都可以使用可变数量的参数进行实例化,这意味着以下所有示例都是有效的:

GlobalFunctionPointer<void> a(&test1);
GlobalFunctionPointer<void, int> b(&test2);
ClassFunctionPointer<void, TestClass, int, char> c(testObject, &TestClass::test1);
ClassFunctionPointer<void, TestClass, int, char, std::string, float, SomeClass> d(testObject, &TestClass::test2);

但是对于这一切,我写了很多代码,大约 500 行,见here。 我发现这很难看,所以我正在寻找一个更优雅的解决方案。 有吗?

(顺便说一句,所有纠结的代码都是为了成为更复杂的事件系统的基础。)

【问题讨论】:

  • 你并不孤单。 VS11 没有可变参数模板,因此它们必须通过一些非常丑陋的宏才能在大多数情况下实现大致相同的行为。
  • 对不起,我无法抗拒。如果你愿意,你可以打败我。但是删除空行呢?会将您的代码从 500 减少到 250!
  • @pbhd:哈哈,我可以这样做,但我发现我的代码中包含这 2000 个空行,可读性更高。

标签: c++ class templates overloading


【解决方案1】:

您正在寻找C++11's variadic templates,正是为此目的而发明的。

或者让单个模板参数T 成为实际的函数类型,然后它可以是void()void(int)void(int, char) 等,随心所欲。

顺便问一下,std::function&lt;T&gt;(或boost::function&lt;T&gt;)有什么问题?这一切都已经解决了。 :-)

【讨论】:

  • 好吧,一方面我对 C++11 不太熟悉,另一方面由于某种原因我不太喜欢它,所以这对我来说不是一个合适的解决方案. // std::function: 呃,我从没听说过,这简直压垮了我到现在为止的所有工作。不过感谢您的回答。 :)
  • @Martin 你应该变得熟悉 C++11。很快。比如,2 年前。
  • @MartinD.:这是一个愚蠢的理由,忽略了正确且全球公认的做事方式。
  • @Lightness Races in Orbit:嗯,C++11 好像从我身边走过。
  • @MartinD.: 至少早在 C++11 之前,人们就一直在使用 boost::function&lt;T&gt;!这是惯用的 C++,至少已经存在了五年。
【解决方案2】:

如果您的编译器不支持variadic templates,那么您可以尝试使用Boost.Preprocessor 库进行仿真。

检查 boost::container::vector::emplace_back 是如何实现的: http://www.boost.org/doc/libs/1_51_0/boost/container/vector.hpp

它使用 Boost.Preprocessor 自动生成带有不同数量参数的函数。它会生成一些预定义数量的函数。

因此,您不必手动编写每个函数。相反,您只能编写一次模式。

例如:

#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>

struct Entity
{
#define ENTITY_PP_PARAM_LIST(z, n, data) const BOOST_PP_CAT(P, n) & BOOST_PP_CAT(p, n)
#define ENTITY_PP_PARAM_PASS(z, n, data) BOOST_PP_CAT(p, n)

#define BOOST_PP_LOCAL_MACRO(n) \
    template<typename GenericType BOOST_PP_ENUM_TRAILING_PARAMS(n, typename P) > \
    void AddComponent(BOOST_PP_ENUM(n, ENTITY_PP_PARAM_LIST, _)) \
    { \
        something=new GenericType(BOOST_PP_ENUM(n, ENTITY_PP_PARAM_PASS, _)); \
    } \
    /**/

#define BOOST_PP_LOCAL_LIMITS (0, 3)
#include BOOST_PP_LOCAL_ITERATE()
};

预处理后展开为:

struct Entity
{
    template<typename GenericType  >
    void AddComponent()
    {
        something=new GenericType();
    }

    template<typename GenericType , typename P0 >
    void AddComponent( const P0 & p0)
    {
        something=new GenericType( p0);
    }

    template<typename GenericType , typename P0 , typename P1 >
    void AddComponent( const P0 & p0 , const P1 & p1)
    {
        something=new GenericType( p0 , p1);
    }

    template<typename GenericType , typename P0 , typename P1 , typename P2 >
    void AddComponent( const P0 & p0 , const P1 & p1 , const P2 & p2)
    {
        something=new GenericType( p0 , p1 , p2);
    }
};

附:我同意“轨道中的轻量级竞赛”,考虑改用 boost/std ::function。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-31
    • 2018-04-28
    • 1970-01-01
    • 2010-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-31
    相关资源
    最近更新 更多