Итак, благодаря С++ 11, теперь можно комбинировать макросы, пользовательские литералы, lambdas и т.д., чтобы создать самое близкое, которое я могу получить до "синтаксического сахара". Пример:
if (A contains B)
Конечно, это легко.
cout <<("hello"_s contains "ello"_s)<<endl;
Выражение преобразуется в bool, где contains - это настраиваемая структура, которая принимает в качестве аргументов левую и правую стороны. Структура курсора перегружает operator +, чтобы сначала взять пользовательский строковый литерал, возвращаясь, а затем оператор + для самой структуры.
struct contains_struct {
string lhs;
string rhs;
void set_lhs(string lhs) { this->lhs = lhs; }
void set_rhs(string rhs) { this->rhs = rhs; }
operator bool() const {
return string::npos != lhs.find(rhs);
}
} contains_obj;
contains_struct& operator+(const string& lhs, const contains_struct& rhs) {
contains_obj.set_lhs(lhs);
return contains_obj;
}
contains_struct& operator+(const contains_struct& lhs, const string& rhs) {
contains_obj.set_rhs(rhs);
return contains_obj;
}
#define contains +contains_obj+
Теперь я решил, что хочу пойти дальше. Что насчет
(x in a) perform cube
Это не понимание списка, но это довольно хороший пример? Сначала я сказал, что мне нужно пойти в stackoverflow, чтобы спросить о пользовательском приоритете оператора, но он прямо поставил его в круглые скобки, так как никто в здравом уме не использовал бы мой код. Вместо этого я расширил свой другой пример и "включил" и "выполнил" как пользовательские структуры, как "содержит".
Вы можете пойти дальше и сделать шаблон таким, чтобы x мог быть любым числовым индексом, а как любой контейнер, но для простоты я оставил x как целое число и a как вектор int. Теперь до сих пор он фактически не принимает локальную переменную x в качестве аргумента, она использует ее локально в функции operator().
Чтобы упростить вещи, я сохраняю результаты выражения в строке, например
operator string() const {
string s = "";
for (int x : lhs.rhs)
s += to_string(rhs(x)) + string("\n");
return s;
}
Благодаря другому вопросу: Перегрузка оператора присваивания для вывода типа
Я понял, что одно практическое использование для его возврата в качестве назначения:
struct result_struct {
vector<int> results;
result_struct(vector<int> results) { this->results = results; }
};
...
operator result_struct() const {
vector<int> tmp;
for (int x : lhs.rhs)
tmp.push_back(rhs(x));
return result_struct(tmp);
}
...
result_struct result_2 = (x in a) perform cube;
for (int x : result_2.results)
cout <<x<<endl;
Благодаря milleniumbug answer, я могу сделать:
struct for_obj
{
int _lhs;
std::vector<int> _rhs;
for_obj(int lhs, std::vector<int> rhs)
: _lhs(lhs), _rhs(rhs) { }
};
INFIX_OPERATOR(for_obj, in_op, int, std::vector<int>)
{
return for_obj(lhs(), rhs());
}
#define in + in_op() +
INFIX_OPERATOR(int, perform_op, for_obj, std::function<int(int)>)
{
for (int i = 0; i < lhs()._rhs.size(); i++)
rhs()(lhs()._rhs[i]);
return 0;
}
#define perform + perform_op() +
Есть два оговорки. Во-первых, я возвращаю int, чтобы я мог назначить его фиктивной переменной, чтобы заставить ее выполнить. Я всегда мог сделать результат result_struct, который я делал раньше, или вернуть объект std:: function, чтобы вызвать его сам по себе, но я бы повторил сам. Другое предостережение состоит в том, что, поскольку в макросе так много consts, вы не можете изменить lhs (что не позволяет вам указать итератор).
Все рассмотренные вещи работают следующим образом.
int x = 0;
std::vector<int> nums = { 1, 2, 3 };
auto cube = [] (int x)
{
std::cout << x * x * x << std::endl;
return x * x * x;
};
int i = (x in nums) perform cube;
Новая версия
class PerformObj {
int counter;
public:
PerformObj() : counter(0) { }
~PerformObj() { }
InObj lhs;
std::function<int(int)> rhs;
operator int() const {
return rhs(lhs.rhs[counter]);
}
} performobj;
#define perform + performobj +
PerformObj& operator+(const InObj& lhs, PerformObj& rhs) {
rhs.lhs = lhs;
return rhs;
}
PerformObj& operator+(PerformObj& lhs, const std::function<int(int)>& rhs) {
lhs.rhs = rhs;
return lhs;
}
int main()
{
std::vector<int> nums = {1,2,3};
int x = 0;
auto cube = [] (int n) {
return n * n * n;
};
std::cout << x in nums perform cube << std::endl;
}
explicit operator std::vector<int>() const {
std::vector<int> temp;
for (int i = 0; i < lhs.rhs.size(); i++) {
temp.push_back(rhs(lhs.rhs[i]));
}
return temp;
}
int y = 0;
std::cout << y in static_cast<std::vector<int>>(x in nums perform cube) perform std::function<int(int)>([] (int i) -> int {
return i;
}) << std::endl;
Должен ли я сделать так, чтобы вместо операторов infix существовали постфиксные операторы, такие как "String literal"s.contains "Other string literal"s
, или выполняли стиль функции, "String literal"s.contains("Other string literal"s)
?
Как я могу улучшить свой код, чтобы сделать его более расширяемым? Как сейчас, он очень загрязнен. Есть ли лучший/более обобщенный/менее неуклюжий способ сделать это? Например, чтобы обобщить выражения так, чтобы мне не нужны инструкции определения или повторное использование кода.