基于参数的C ++预处理器条件扩展

时间:2015-12-24 14:35:23

标签: c++ macros metaprogramming c-preprocessor boost-preprocessor

我有一个正在为我构建课程的宏。我想提供一个构造函数,如果类本身没有指定 int 作为其类型,则该构造函数接受 int 。宏看起来像:

CLASS_DECLARE(NAME, TYPE)\
  class NAME { \
  public: NAME(const TYPE& x) : value(x) {}\
  BOOST_PP_EXPR_IF(BOOST_PP_NOT_EQUAL(TYPE, int), NAME(const int& x) : value(static_cast<TYPE>(x)) {})\
  private: TYPE value; };

我可以使用boost预处理器来接近手动打开和关闭此构造函数...

    BOOST_PP_EXPR_IIF_BOOST_PP_BOOL_BOOST_PP_NOT_EQUAL_CHECK_BOOST_PP_NOT_EQUAL_int(0, 
BOOST_PP_NOT_EQUAL_int)(MyType(const int& x) : value(static_cast<int>(x)){};

但是,我不能用条件替换宏中的 0 。我想要这样的东西:

 HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost("your url");
        List<NameValuePair> nameValuePair = new ArrayList<NameValuePair>();

        nameValuePair.add(new BasicNameValuePair("username",    "username"));
        nameValuePair.add(new BasicNameValuePair("lang", "en"));

        httpPost.setEntity(new UrlEncodedFormEntity(nameValuePair));
        UrlEncodedFormEntity ent = new UrlEncodedFormEntity(nameValuePair);
        HttpResponse response = httpClient.execute(httpPost);

然而,这扩展到不太有用的东西:

{{1}}

环顾四周,似乎没有BOOST_PP_NOT_EQUAL用于此类比较。 (我知道宏扩展问题,并且已经建立了一些&#34; IMPL&#34;宏来试图让事情进一步扩展。但是,我不认为这是问题所在。)思考?

2 个答案:

答案 0 :(得分:1)

如果其他人有问题需要这种专业化,我想发一个答案。如果您想要比较一组有限的类型/字符串并在编译时知道它们,那么此解决方案将起作用。这是支持int和uint8_t的示例。特殊构造函数只能为非int类型编写。

#include <boost/preprocessor.hpp>

#define TYPE_IS_int 0
#define TYPE_IS_uint8_t 1

#define CLASS_DECLARE(NAME, TYPE)\
    class NAME {\
        public: NAME(const TYPE& x) : value(x) {}\
        BOOST_PP_EXPR_IF(BOOST_PP_CAT(TYPE_IS_, BOOST_PP_EXPAND(TYPE)), NAME(const int& x) : value(static_cast<TYPE>(x)) {})\
        private: TYPE value; };

CLASS_DECLARE(MyIntType, int);
CLASS_DECLARE(MyUint8Type, uint8_t);

宏扩展为:

class MyIntType
{ 
    public: 
        MyIntType(const int& x) : value(x) {}  
    private: 
        int value; 
};

class MyUint8Type 
{ 
    public: 
        MyUint8Type(const uint8_t& x) : value(x) {} 
        MyUint8Type(const int& x) : value(static_cast<uint8_t>(x)) {} 
    private: 
        uint8_t value; 
};

答案 1 :(得分:0)

我能够通过使int中明确声明的构造函数不太受欢迎来解决这个问题。为此,我声明了一个可以从int构造并转换回int的简单类,然后在构造函数中使用此类而不是普通int

struct int_wrapper {
    int value;
    operator int() const { return value; }
    int_wrapper(int x): value(x) {}
};

#define CLASS_DECLARE(NAME, TYPE)\
  class NAME { \
  public: \
    NAME(const TYPE& x) : value(x) {}\
    NAME(const int_wrapper& x) : value(static_cast<TYPE>(x)) {} \
  private: \
    TYPE value; \
  };

这允许

CLASS_DECLARE(cfloat, float)
CLASS_DECLARE(cint, int)

int main()
{
    cfloat f1(1.0);
    cfloat f2(1);
    cint i(2);
}

Live on Coliru

虽然请注意,如果您尝试传递自己的已声明operator int()的类,则会产生问题。你原来的方法可以处理这个(将类转换为int并调用int构造函数),而我的方法不会,因为编译器不允许两个用户定义的转换(到int然后到int_wrapper)。

此外,我现在无法获得第二个被调用的构造函数,因为如果你有static_cast<TYPE>(x),这意味着每int TYPE应该可以转换为TYPE你使用,但第一个构造函数就足够了。但是,如果您的第二个构造函数只是一个简化的示例,而您实际上并没有直接将TYPE强制转换为int,那么您可能会发现我的答案很有用。