【问题标题】:How can I take a decision based on a type within a macro?如何根据宏中的类型做出决定?
【发布时间】:2014-10-20 22:11:16
【问题描述】:

在我的公司,我正在努力为一些热门代码提供更快的 SSE 路径。我正在使用与 C++ 保持一致的内在方法,并且确实显示出令人印象深刻的结果。

所有代码只需要在floatdouble 上工作,所以我创建了一个模板化的 SSE 操作类,我专门针对这两个类。我真正不喜欢的是这两个类看起来几乎相同,除了数字类型(float/double)、使用的 SSE 类型(__m128/__m128d)和 intrisics 后缀(@987654328 @/_pd) 像这样:

template<>
struct SseOperations<float> : public Sse<float>
{
    typedef __m128 vector;

    vector load(float const * const from) const
    {
        return _mm_loadu_ps(from);
    }

    vector add(vector const & a, vector const & b) const
    {
        return _mm_add_ps(a, b);
    }

    // etc.
};

template<>
struct SseOperations<double> : public Sse<double>
{
    typedef __m128d vector;

    vector load(double const * const from) const
    {
        return _mm_loadu_pd(from);
    }

    vector add(vector const & a, vector const & b) const
    {
        return _mm_add_pd(a, b);
    }

    // etc.
};

由于内部函数后缀不同,我不知道如何使用模板魔法来统一它。

然后我想到了宏的## 功能,它可以用于此目的。所以我设法将完整的专业类放入一个宏中,我可以用它来生成两个类:

SSE_OPERATIONS(float, __m128, _ps);
SSE_OPERATIONS(double, __m128d, _pd);

我知道宏是邪恶的,但至少在这种情况下我没有看到任何典型的危险并且它完成了工作。

现在困扰我的是第二个和第三个宏参数是多余的;它们可以从第一个推断出来,只是我完全不知道如何。 #if 及其朋友不应该工作,因为 sizeof() 在预处理期间不起作用。

搜索解决方案出乎意料地困难,因为#if 主题严重污染了结果。谁能告诉我如何针对这个问题做出宏观决策?

PS:我听说过Boost Preprocessor,但我不能使用它。

更新:虽然我要求的是宏解决方案,但我也会接受一个不错的模板解决方案。为此,要知道我封装了至少 7 个内部函数——以防模板代码膨胀。

【问题讨论】:

  • 如果你可以用宏来做到这一点,你也可以不用宏来做到这一点。
  • 我看不出宏参数是如何冗余的。这 3 个名称在令牌级别上完全不相关。您的宏必须必须说明这 3 个令牌之间的逻辑关系。你不能从`float. Of course, this ultimately is caused by the extremely limited integration of SSE primitives and C++. If the responsible compiler developer had understood both, he'd have realized that operator+`中推断出_ps_mm_add_pd的一个完全理智的名字。运算符重载已有数十年历史;今天无需继续对程序施加汇编程序限制。
  • 好吧,它们对 PP 来说不是多余的,但对我来说。如果我有一个宏 if,我可以只在给定 floatdouble 的宏的开头计算/设置它们。

标签: c++ if-statement c++11 macros code-generation


【解决方案1】:

你可以通过 trait 去掉第二个参数:

template <class Scalar>
struct Vector;

template <>
struct Vector<float>
{
  typedef __m128 type;
};

template <>
struct Vector<double>
{
  typedef __m128d type;
};

至于第三个,你可以做一个非常ugly的特殊预处理器hack技巧:

#define SUFFIX_float ps
#define SUFFIX_double pd

并在SUFFIX_ 上使用## 和最外层的宏参数以达到正确的版本。当然,它需要一些间接级别才能让宏在正确的时间展开。使用 Boost.Preprocessor,尤其是 BOOST_PP_CAT 和可能的 BOOST_PP_EXPAND,可能会稍微容易一些。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-16
    • 2011-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-02
    • 2018-07-03
    • 1970-01-01
    相关资源
    最近更新 更多