如何在传递给C/C++宏之前解析int变量?

Shu*_*wal -3 c++ c-preprocessor

我正在尝试执行以下代码:

#define channel1 10
#define channel(id) channel##id

int main(){
    int id = 1;
    cout << channel(id)<<"\n";

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我收到以下错误: error: use of undeclared identifier 'channelid'

相反,我希望输出为10,channel(id)应该预处理,channel1并用10替换值.

有没有办法实现它?

jsa*_*der 8

之所以会出现此问题,是因为您尝试混合在处理代码的不同阶段考虑的信息.

宏和所有CPP(C-Pre-Processor)事件发生(正如其自己的名称所示)之前的事情.它对变量值一无所知(最多关于#define),它的大部分内容都是文本争论.

一些变量值可能在编译时已知(参见参考资料constexpr)......但大多数变量值只能在运行时知道.

因此,总之,您的代码会失败,因为预处理器对id变量一无所知.

编辑:解释总和示例.

我们有这个代码 x.cpp

#define sum(a,b) a + b

int main(int argc, char **argv) {
 int x = 1, y = 2;
 return sum(x,y);    
}
Run Code Online (Sandbox Code Playgroud)

这段代码编译并正常工作.

让我们来看看幕后发生的事情.

所有C/C++源文件都经过预处理.这意味着它们使用与C或C++不同的语言进行评估:CPP(C预处理器).这个CPP负责所有#...东西(例如搜索和包含头文件),正如我所说的,与C或C++无关.

实际上,你甚至可以在没有编译器的情况下运行它(尝试cpp x.cpp),或者你可以指示编译器只执行这个阶段(g++ -o x.i -E x.cpp)

如果我们看看xi:

# 1 "x.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "x.cpp"


int main(int argc, char **argv) {
 int x = 1, y = 2;
 return x + y;

}
Run Code Online (Sandbox Code Playgroud)

我们可以观察几件事:

  1. 还有一些额外的'#'行.编译器使用这些来跟踪所有内容的来源以及所包含位的来源,以便能够提供有意义的错误消息.
  2. 请注意我们的sum宏如何在代码中被替换.这是盲目完成的,结果字符串被证明是不正确的C/C++语法,它不会被检测到,但只有在完成实际的C/C++解析时才会被检测到.


Lig*_*ica 7

简单来说,解决方案不是这样做的.

宏无法使用显示分钟,小时,天,年,可能数十年后的值.在编译之前解析宏,在编译之前无法知道值是什么id.在编译期间排序,但即使这样,它也会变得复杂,除非初始化器是微不足道的,并且变量的值永远不会改变.

相反,使用一个函数:

#include <iostream>
#include <stdexcept>

int channel(const int id)
{
   // Your own rules here; we don't know enough about them to know.
   // Perhaps instead of a switch, a map. It depends.
   switch (id)
   {
      case 1:  return 10;
      default: throw std::out_of_range("Dammit");
   }
}

int main()
{
    int id = 1;
    std::cout << channel(id) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

同样,如果在编译时已知, 可以使它在编译时工作id,并使用关键字指示constexpr:

#include <iostream>
#include <stdexcept>

template <int id>
int channel()
{
   // Perhaps instead of a switch, a sequence of 'if constexpr' and
   // a static_assert(false) at the end.
   switch (id)
   {
      case 1:  return 10;
      default: throw std::out_of_range("Rats");
   }

}

int main()
{
    constexpr int id = 1;
    std::cout << channel<id>() << '\n';
}
Run Code Online (Sandbox Code Playgroud)

如果两种方法都不可接受,那么您必须重新修改您的要求.

但是,如果不知道这些要求究竟是什么,我们就无法帮助您做到这一点.

  • @tadman:非常,如果`channel`现在可以成为一个功能模板 (2认同)