删除括号的c ++宏
c++ macro that removes parentheses
假设我的 .cpp 代码中某处有这样的东西
name(min,max)
我可以写一个宏吗?
#define GET_NAME(A) //transforms name(min,max) -> name;
还有宏?
#define GET_RANGE(A) // transforms name(min,max) -> std::pair<T,N>(min,max);
用法应该是这样的
GET_NAME(r(0,255)) -> r
GET_RANGE(r(0,255)) -> std::pair<int,int>(0,255)
真正的目标是提供这样的东西
#ifndef PIXEL_PIXEL_HPP
#define PIXEL_PIXEL_HPP
#include <ostream>
#include <array>
template<typename T, unsigned int N>
union Pixel;
#define DECLARE_PIXEL(NAME, T, N, ...) \
template<> \
union Pixel<T,N> { \
static const int SIZE = N;\
T args[N]; \
struct{ \
T __VA_ARGS__;\
};\
\
Pixel() = default; \
Pixel(std::initializer_list<T> l) { std::move(l.begin(),l.end(),args); }; \
Pixel(const Pixel<T,N>& other) = default; \
Pixel(Pixel<T,N>&& other) = default; \
T operator[](unsigned int i) const{ \
return args[i];\
} \
T& operator[](unsigned int i) { \
return args[i];\
}\
bool operator==(const Pixel<T,N>& rhs) const{ \
for(int i = 0; i < N; ++i) { \
if(args[i] != rhs[i]) { \
return false; \
} \
} \
return true; \
}; \
bool operator!=(const Pixel<T,N>& rhs) const{ \
return !(*this == rhs); \
}; \
bool operator<(const Pixel<T,N>& rhs) const{ \
for(int i = 0; i < N; ++i) { \
if(args[i] >= rhs[i]) { \
return false;\
}\
} \
return true;\
}; \
bool operator>(const Pixel<T,N>& rhs) const{ \
for(int i = 0; i < N; ++i) { \
if(args[i] <= rhs[i]) { \
return false;\
}\
} \
return true;\
}; \
bool operator<=(const Pixel<T,N>& rhs) const{ \
return !(*this > rhs);\
}; \
bool operator>=(const Pixel<T,N>& rhs) const{ \
return !(*this < rhs);\
}; \
Pixel<T,N>& operator=(const Pixel<T,N>& rhs) = default; \
Pixel<T,N>& operator=(Pixel<T,N>&& rhs) = default; \
Pixel<T,N> operator*(T scalar) const{ \
Pixel<T,N> result; \
for(int i = 0; i < N; ++i) { \
result[i] = static_cast<T>(args[i] * scalar); \
} \
return result;\
}; \
friend Pixel<T,N> operator*(T scalar, const Pixel<T,N>& rhs){ \
return rhs * scalar;\
}\
Pixel<T,N> operator*(const Pixel<T,N>& other) const { \
Pixel<T,N> result;\
for(int i = 0; i < N; ++i) { \
result[i] = static_cast<T>(args[i] * other[i]);\
} \
return result;\
};\
Pixel<T,N> operator/(T scalar) const { \
return (*this) * (1/scalar);\
}; \
friend Pixel<T,N> operator/(T scalar, const Pixel<T,N>& pixel) { \
return pixel / scalar;\
}\
Pixel<T,N> operator/(const Pixel<T,N>& other) const { \
Pixel<T,N> result; \
for(int i = 0; i < N; ++i) { \
result[i] = static_cast<T>(args[i] / other[i]);\
} \
return result;\
};\
Pixel<T,N> operator+(const Pixel<T,N>& rhs) const { \
Pixel<T,N> result; \
for(int i = 0; i < N; ++i) { \
result[i] = static_cast<T>(args[i] + rhs[i]); \
} \
return result;\
}; \
Pixel<T,N> operator-(const Pixel<T,N>& rhs) const { \
Pixel<T,N> result; \
for(int i = 0; i < N; ++i) { \
result[i] = static_cast<T>(args[i] - rhs[i]);\
} \
return result; \
} \
Pixel<T,N>& operator +=(const Pixel<T,N>& rhs) { \
*this = *this + rhs; \
return *this;\
} \
Pixel<T,N>& operator -=(const Pixel<T,N>& rhs) { \
*this = *this - rhs; \
return *this;\
} \
Pixel<T,N>& operator *=(const Pixel<T,N>& rhs) { \
*this = *this * rhs; \
return *this;\
} \
Pixel<T,N>& operator /=(const Pixel<T,N>& rhs) { \
*this = *this / rhs; \
return *this;\
}\
friend std::ostream& operator<<(std::ostream& os, const Pixel<T,N>& pixel) { \
for(const auto& elem : pixel.args){ \
os<<elem << " "; \
} \
return os;\
} \
\
}; \
using NAME = Pixel<T,N>; \
DECLARE_PIXEL(RGB, int, 3,r(0,255), g(0,255), b(0,255))
DECLARE_PIXEL(ARGB, float, 4, a(0,1), r(0,1), g(0,1), b(0,1))
#undef DECLARE_PIXEL
#endif //PIXEL_PIXEL_HPP
并且还会有一些新的像素类型,例如 HSL。
请注意,变量的范围部分将存储为成对的静态向量,而变量的名称将存储在结构中。
不,宏不能做到这一点。如果您愿意稍微更改语法,例如,将 r(0,255)
写成 (r)((0,255))
或 (r,(0,255))
那么这是可行的。例如,参见 Boost Preprocessor library 文档。
您将无法直接编写 T __VA_ARGS__;
,您需要迭代参数(Boost 预处理器也可以这样做)。
话虽如此,无论问题是什么,宏几乎都不是一个好的答案。
注意:这个答案被接受后我重写了它以使其更简单。
我建议不要为此使用单个宏或 union
,而是向数组中的特定元素添加访问器。
您可以在 Pixel
class 模板中实现基本成员函数,并继承 rgb
和 argb
classes 保存数组和实现访问器。
示例:
#include <array>
#include <iostream>
template<typename T>
struct Pixel : public T {
static constexpr size_t SIZE = sizeof(T);
// only methods here, no non-static member variables
// iterators
auto cbegin() const { return this->arr.cbegin(); }
auto cend() const { return this->arr.cend(); }
auto begin() const { return cbegin(); }
auto end() const { return cend(); }
auto begin() { return this->arr.begin(); }
auto end() { return this->arr.end(); }
// an example of a function adding one Pixel to another
Pixel& operator+=(const Pixel& rhs) {
auto rit = rhs.begin();
for(auto& v : this->arr) v += *rit++;
return *this;
}
};
// make the functions returning a new object into free functions
template<typename T>
Pixel<T> operator+(const Pixel<T>& a, const Pixel<T>& b) {
Pixel rv = a;
rv += b;
return rv;
}
// streaming the values in a Pixel<T>
template<typename T>
std::ostream& operator<<(std::ostream& os, const Pixel<T>& p) {
os << '{';
auto it = p.cbegin();
if constexpr(sizeof(*it) == 1) os << static_cast<int>(*it);
else os << *it;
for(++it; it != p.cend(); ++it) {
os << ',';
if constexpr(sizeof(*it) == 1) os << static_cast<int>(*it);
else os << *it;
}
return os << '}';
}
然后用访问器定义rgb
和argb
:
struct rgb {
std::uint8_t& r() { return arr[0]; }
std::uint8_t& g() { return arr[1]; }
std::uint8_t& b() { return arr[2]; }
std::uint8_t r() const { return arr[0]; }
std::uint8_t g() const { return arr[1]; }
std::uint8_t b() const { return arr[2]; }
std::array<std::uint8_t, 3> arr;
};
struct argb {
float& a() { return arr[0]; }
float& r() { return arr[1]; }
float& g() { return arr[2]; }
float& b() { return arr[3]; }
float a() const { return arr[0]; }
float r() const { return arr[1]; }
float g() const { return arr[2]; }
float b() const { return arr[3]; }
std::array<float, 4> arr;
};
用法示例:
int main() {
Pixel<rgb> x {{126,127,128}};
Pixel<rgb> y {{129,128,127}};
Pixel<rgb> z = x + y;
Pixel<argb> foo {{1.1f, 2.2f, 3.3f, 4.4f}};
Pixel<argb> bar {{1.1f, 2.2f, 3.3f, 4.4f}};
foo += bar;
std::cout << z << '\n';
std::cout << foo << '\n';
std::cout << sizeof(z) << '\n';
}
可能的输出:
{255,255,255}
{2.2,4.4,6.6,8.8}
3
假设我的 .cpp 代码中某处有这样的东西
name(min,max)
我可以写一个宏吗?
#define GET_NAME(A) //transforms name(min,max) -> name;
还有宏?
#define GET_RANGE(A) // transforms name(min,max) -> std::pair<T,N>(min,max);
用法应该是这样的
GET_NAME(r(0,255)) -> r
GET_RANGE(r(0,255)) -> std::pair<int,int>(0,255)
真正的目标是提供这样的东西
#ifndef PIXEL_PIXEL_HPP
#define PIXEL_PIXEL_HPP
#include <ostream>
#include <array>
template<typename T, unsigned int N>
union Pixel;
#define DECLARE_PIXEL(NAME, T, N, ...) \
template<> \
union Pixel<T,N> { \
static const int SIZE = N;\
T args[N]; \
struct{ \
T __VA_ARGS__;\
};\
\
Pixel() = default; \
Pixel(std::initializer_list<T> l) { std::move(l.begin(),l.end(),args); }; \
Pixel(const Pixel<T,N>& other) = default; \
Pixel(Pixel<T,N>&& other) = default; \
T operator[](unsigned int i) const{ \
return args[i];\
} \
T& operator[](unsigned int i) { \
return args[i];\
}\
bool operator==(const Pixel<T,N>& rhs) const{ \
for(int i = 0; i < N; ++i) { \
if(args[i] != rhs[i]) { \
return false; \
} \
} \
return true; \
}; \
bool operator!=(const Pixel<T,N>& rhs) const{ \
return !(*this == rhs); \
}; \
bool operator<(const Pixel<T,N>& rhs) const{ \
for(int i = 0; i < N; ++i) { \
if(args[i] >= rhs[i]) { \
return false;\
}\
} \
return true;\
}; \
bool operator>(const Pixel<T,N>& rhs) const{ \
for(int i = 0; i < N; ++i) { \
if(args[i] <= rhs[i]) { \
return false;\
}\
} \
return true;\
}; \
bool operator<=(const Pixel<T,N>& rhs) const{ \
return !(*this > rhs);\
}; \
bool operator>=(const Pixel<T,N>& rhs) const{ \
return !(*this < rhs);\
}; \
Pixel<T,N>& operator=(const Pixel<T,N>& rhs) = default; \
Pixel<T,N>& operator=(Pixel<T,N>&& rhs) = default; \
Pixel<T,N> operator*(T scalar) const{ \
Pixel<T,N> result; \
for(int i = 0; i < N; ++i) { \
result[i] = static_cast<T>(args[i] * scalar); \
} \
return result;\
}; \
friend Pixel<T,N> operator*(T scalar, const Pixel<T,N>& rhs){ \
return rhs * scalar;\
}\
Pixel<T,N> operator*(const Pixel<T,N>& other) const { \
Pixel<T,N> result;\
for(int i = 0; i < N; ++i) { \
result[i] = static_cast<T>(args[i] * other[i]);\
} \
return result;\
};\
Pixel<T,N> operator/(T scalar) const { \
return (*this) * (1/scalar);\
}; \
friend Pixel<T,N> operator/(T scalar, const Pixel<T,N>& pixel) { \
return pixel / scalar;\
}\
Pixel<T,N> operator/(const Pixel<T,N>& other) const { \
Pixel<T,N> result; \
for(int i = 0; i < N; ++i) { \
result[i] = static_cast<T>(args[i] / other[i]);\
} \
return result;\
};\
Pixel<T,N> operator+(const Pixel<T,N>& rhs) const { \
Pixel<T,N> result; \
for(int i = 0; i < N; ++i) { \
result[i] = static_cast<T>(args[i] + rhs[i]); \
} \
return result;\
}; \
Pixel<T,N> operator-(const Pixel<T,N>& rhs) const { \
Pixel<T,N> result; \
for(int i = 0; i < N; ++i) { \
result[i] = static_cast<T>(args[i] - rhs[i]);\
} \
return result; \
} \
Pixel<T,N>& operator +=(const Pixel<T,N>& rhs) { \
*this = *this + rhs; \
return *this;\
} \
Pixel<T,N>& operator -=(const Pixel<T,N>& rhs) { \
*this = *this - rhs; \
return *this;\
} \
Pixel<T,N>& operator *=(const Pixel<T,N>& rhs) { \
*this = *this * rhs; \
return *this;\
} \
Pixel<T,N>& operator /=(const Pixel<T,N>& rhs) { \
*this = *this / rhs; \
return *this;\
}\
friend std::ostream& operator<<(std::ostream& os, const Pixel<T,N>& pixel) { \
for(const auto& elem : pixel.args){ \
os<<elem << " "; \
} \
return os;\
} \
\
}; \
using NAME = Pixel<T,N>; \
DECLARE_PIXEL(RGB, int, 3,r(0,255), g(0,255), b(0,255))
DECLARE_PIXEL(ARGB, float, 4, a(0,1), r(0,1), g(0,1), b(0,1))
#undef DECLARE_PIXEL
#endif //PIXEL_PIXEL_HPP
并且还会有一些新的像素类型,例如 HSL。 请注意,变量的范围部分将存储为成对的静态向量,而变量的名称将存储在结构中。
不,宏不能做到这一点。如果您愿意稍微更改语法,例如,将 r(0,255)
写成 (r)((0,255))
或 (r,(0,255))
那么这是可行的。例如,参见 Boost Preprocessor library 文档。
您将无法直接编写 T __VA_ARGS__;
,您需要迭代参数(Boost 预处理器也可以这样做)。
话虽如此,无论问题是什么,宏几乎都不是一个好的答案。
注意:这个答案被接受后我重写了它以使其更简单。
我建议不要为此使用单个宏或 union
,而是向数组中的特定元素添加访问器。
您可以在 Pixel
class 模板中实现基本成员函数,并继承 rgb
和 argb
classes 保存数组和实现访问器。
示例:
#include <array>
#include <iostream>
template<typename T>
struct Pixel : public T {
static constexpr size_t SIZE = sizeof(T);
// only methods here, no non-static member variables
// iterators
auto cbegin() const { return this->arr.cbegin(); }
auto cend() const { return this->arr.cend(); }
auto begin() const { return cbegin(); }
auto end() const { return cend(); }
auto begin() { return this->arr.begin(); }
auto end() { return this->arr.end(); }
// an example of a function adding one Pixel to another
Pixel& operator+=(const Pixel& rhs) {
auto rit = rhs.begin();
for(auto& v : this->arr) v += *rit++;
return *this;
}
};
// make the functions returning a new object into free functions
template<typename T>
Pixel<T> operator+(const Pixel<T>& a, const Pixel<T>& b) {
Pixel rv = a;
rv += b;
return rv;
}
// streaming the values in a Pixel<T>
template<typename T>
std::ostream& operator<<(std::ostream& os, const Pixel<T>& p) {
os << '{';
auto it = p.cbegin();
if constexpr(sizeof(*it) == 1) os << static_cast<int>(*it);
else os << *it;
for(++it; it != p.cend(); ++it) {
os << ',';
if constexpr(sizeof(*it) == 1) os << static_cast<int>(*it);
else os << *it;
}
return os << '}';
}
然后用访问器定义rgb
和argb
:
struct rgb {
std::uint8_t& r() { return arr[0]; }
std::uint8_t& g() { return arr[1]; }
std::uint8_t& b() { return arr[2]; }
std::uint8_t r() const { return arr[0]; }
std::uint8_t g() const { return arr[1]; }
std::uint8_t b() const { return arr[2]; }
std::array<std::uint8_t, 3> arr;
};
struct argb {
float& a() { return arr[0]; }
float& r() { return arr[1]; }
float& g() { return arr[2]; }
float& b() { return arr[3]; }
float a() const { return arr[0]; }
float r() const { return arr[1]; }
float g() const { return arr[2]; }
float b() const { return arr[3]; }
std::array<float, 4> arr;
};
用法示例:
int main() {
Pixel<rgb> x {{126,127,128}};
Pixel<rgb> y {{129,128,127}};
Pixel<rgb> z = x + y;
Pixel<argb> foo {{1.1f, 2.2f, 3.3f, 4.4f}};
Pixel<argb> bar {{1.1f, 2.2f, 3.3f, 4.4f}};
foo += bar;
std::cout << z << '\n';
std::cout << foo << '\n';
std::cout << sizeof(z) << '\n';
}
可能的输出:
{255,255,255}
{2.2,4.4,6.6,8.8}
3