有没有一种方法可以将此转换为“;为我而言";c++;从预处理器宏到现代C++;(11+;)? 我正在寻找一种方法,用更现代的东西来替换这个C++预处理器宏。 #define fori(FORI_TYPE, FORI_FROM, FORI_TO) \ for(FORI_TYPE i{FORI_FROM}; \ ((FORI_FROM) < (FORI_TO)) ? (i < (FORI_TO)) : (i > (FORI_TO)); \ ((FORI_FROM) < (FORI_TO)) ? ++i : --i ) #定义fori(fori_类型、fori_FROM、fori_TO)\ for(FORI_类型i{FORI_FROM}\ (从)到…)(我到…):(我到…)\ ((FORI_FROM)结束值?-1:1) {} iter begin(){返回iter(begin_val,step_val);} iter end(){return iter(end_val,step_val);} }; int main() { 用于(自动i:范围(42,10)) std::cout

有没有一种方法可以将此转换为“;为我而言";c++;从预处理器宏到现代C++;(11+;)? 我正在寻找一种方法,用更现代的东西来替换这个C++预处理器宏。 #define fori(FORI_TYPE, FORI_FROM, FORI_TO) \ for(FORI_TYPE i{FORI_FROM}; \ ((FORI_FROM) < (FORI_TO)) ? (i < (FORI_TO)) : (i > (FORI_TO)); \ ((FORI_FROM) < (FORI_TO)) ? ++i : --i ) #定义fori(fori_类型、fori_FROM、fori_TO)\ for(FORI_类型i{FORI_FROM}\ (从)到…)(我到…):(我到…)\ ((FORI_FROM)结束值?-1:1) {} iter begin(){返回iter(begin_val,step_val);} iter end(){return iter(end_val,step_val);} }; int main() { 用于(自动i:范围(42,10)) std::cout,c++,c-preprocessor,C++,C Preprocessor,理想情况下,我可以摆脱所有的?操作符(constexpr在这里有用吗?),并且“fori”不会像现在proceprocessor版本那样产生任何间接成本(操作符的评估)。还有,类型安全 用法示例: fori(size_t, 0, n) { cout << i << endl; } fori(大小为0,n) { cout无论如何,您总是需要知道迭代的方向,所以您无法摆脱这种开销。也就是说,通过切换宏,您至少可以更轻松地进行优化(部分通过输入const来促进重复/类

理想情况下,我可以摆脱所有的?操作符(constexpr在这里有用吗?),并且“fori”不会像现在proceprocessor版本那样产生任何间接成本(操作符的评估)。还有,类型安全

用法示例:

fori(size_t, 0, n)
{
    cout << i << endl;
}
fori(大小为0,n)
{

cout无论如何,您总是需要知道迭代的方向,所以您无法摆脱这种开销。也就是说,通过切换宏,您至少可以更轻松地进行优化(部分通过输入
const
来促进重复/类似条件的折叠,部分通过预先计算“步长”距离来完全消除其中一些条件)

就宏而言,这一个还不错(尽管它可能使用一个
()
或两个…)

真正“现代”的做法是使用,或

例如,天真地改编Neil的代码以提供自动步进方向检测:

#include <iostream>

template <class T>
class range
{
private:
    class iter
    {
    private:
        T at, step;
    public:
        iter(T at, T step) : at(at), step(step) {}
        bool operator!=(iter const& other) const { return at != other.at; }
        T const& operator*() const { return at; }
        iter& operator++() { at += step; return *this; }
    };

    T begin_val;
    T end_val;
    T step_val;

public:

    range(const T begin_val, const T end_val)
        : begin_val(begin_val)
        , end_val(end_val)
        , step_val(begin_val > end_val ? -1 : 1)
    {}

    iter begin() { return iter(begin_val, step_val); }
    iter end() { return iter(end_val, step_val); }
};

int main()
{
   for (auto i : range<unsigned>(42, 10))
      std::cout << i << ' ';
   std::cout << '\n';
}

// Output: 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 
#包括
模板
等级范围
{
私人:
类iter
{
私人:
T在,步骤;
公众:
iter(at,T步):at(at),step(step){
布尔运算符!=(iter const&other)const{return at!=other.at;}
T常量&运算符*()常量{return at;}
iter&operator++(){at+=step;返回*this;}
};
不要开始;
T结束值;
T阶跃值;
公众:
范围(常数开始值、常数结束值)
:开始值(开始值)
,end_val(end_val)
,步骤值(开始值>结束值?-1:1)
{}
iter begin(){返回iter(begin_val,step_val);}
iter end(){return iter(end_val,step_val);}
};
int main()
{
用于(自动i:范围(42,10))

std::cout我们可以通过使用模板来摆脱宏,尽管这确实意味着必须添加回调函数

//f is of the form void func(int i)
template <typename T, typename F>
void fori(const T from, const T to, F f)
{
    for(
        T i  = from;
        (from < to) ? (i < to) : (i > to);
        (form < to) ? ++i : --i 
    ) {
         f(i);
 }
//f的形式为void func(int i)
模板
无效fori(常数从,常数到,F)
{
为了(
T i=来自;
(从<到)?(i<到):(i>到);
(表<至)?++i:--i
) {
f(i);
}
用法:

fori<int>(1, 20, [](int i) {
    std::cout << i << std::endl;
});
fori(1,20,[](inti){

std::cout要生成类型的序列,我们需要使用生成器。的范围将使用其输出:

for(auto i: range<size_t>(0, n)) {
  std::cout << n << " ";
}
for(自动i:范围(0,n)){

std::您是否需要迭代范围内的所有数字,或者您打算使用
i
作为容器的索引(即,您希望迭代项目)?宏用于各种各样的上下文,它可以用作索引或计算,无论什么。这是用于多项目范围内的用途。@Aziuth将其更改为什么,我认为这是一个个人建议:不要。不要。宏很糟糕,因为它们很难编写、读取和调试,但如果它们满足您的需要,就使用它们。现代C++元编程肯定比旧的C预处理器宏好一些,但是代码并不容易理解或调试…如果你想改变一些东西,就让程序员使用语言。用元编程只保存几个字符,呃……我不喜欢。你可以考虑使用<代码> IoTaYVIEW/<代码>。它被添加到C++20中,您总是需要知道迭代的方向,所以您无法摆脱这种开销-如果所有的边界都在编译时给出,那么实现没有理由不在没有分支的情况下就不能相应地调整迭代器。您将在编译时需要该分支,但有ally没有理由将其带到生成的运行时代码中。@ComicSanms使用“
n
”我假设它们在编译时不为人所知,但如果不是这样,您当然是对的。感谢您的澄清!您也可以删除第一个
?:
,只需将其替换为
from!=to
for(auto i: range<size_t>(0, n)) {
  std::cout << n << " ";
}
template <typename T> class range {
  T a, b;
public:
  typename wrap<T> begin() const { return a; }
  typename wrap<T> end() const { return b; }
};