【问题标题】:Is it possible to make macros that are default arguments expand at call site?是否可以在调用站点扩展默认参数的宏?
【发布时间】:2019-04-23 06:08:41
【问题描述】:
#include <stdio.h>

void print(int a = __LINE__){printf("hello %d\n", a);}

void main(){
  print();
  print();
  print();
  print();
}

本例中的 __LINE__ 宏扩展为 3,因此 print 函数以相同的值被调用了 4 次。有没有办法说服编译器在调用点扩展此宏,以便使用 C++11 中存在的功能使用 6,7,8,9 而不是 3,3,3,3 调用打印函数?

我的用例:

在我的应用程序中,我提供了多个采用唯一 ID 的函数。每个调用点/位置的 ID 应该是唯一的(因此,如果通过同一语句调用该函数两次,它应该接收相同的 ID)。目前,用户必须在调用点手动输入LOCATION 宏,如下所示:

#define S1(x) #x //voodoo to concat __FILE__ and __LINE__
#define S2(x) S1(x)
#define LOCATION __FILE__ S2(__LINE__)

do_stuff1(arguments, LOCATION)
do_stuff2(arguments, LOCATION)

如果我可以保存他们的输入,而不为每个函数创建一个宏,这样会更方便:

#define do_stuff1(do_stuff1_imp(arguments, LOCATION))
#define do_stuff2(do_stuff2_imp(arguments, LOCATION))

因此,我认为默认参数可以解决问题。有什么方法可以实现吗?

【问题讨论】:

  • 在宏中完成工作,#define print() {printf("hello %d\n", __LINE__);}
  • 这正是我在最后一个代码块中写的,只是在do_stuff而不是print上翻译。我知道这个解决方案,并想知道是否有一种不那么乏味的方法来做到这一点(我有很多这样的功能。我需要为每个功能制作一个宏)。
  • 等等,不,对不起,我错了。你的方式使整个函数成为一个宏。那确实不一样。我会考虑的,谢谢!
  • @MatthieuBrucher 不要像那样将标签从 C++ 更改为 C。即使问题中的所有代码都可以使用 C 编译器进行编译,但这并不会使问题成为 C 问题(请注意,默认参数是 C++ 功能)。 OP 正在使用 C++ 编译器,并且正在寻找 C++ 答案,而不是 C。

标签: c++ c++11 macros default-arguments std-source-location


【解决方案1】:

您似乎在寻找std::experimental::source_location,在未来的标准中将是std::source_location

#include <experimental/source_location>

void print(std::experimental::source_location const& location
    = std::experimental::source_location())
{
    printf("hello %s:%d\n", location.file_name(), location.line());
}

【讨论】:

  • 这确实是我想要的。不过,我将无法使用 C++17(我认为这需要吗?)。对不起,我忘了在问题中提到这一点。不过,我会牢记这一点。谢谢!
  • @pulp_user 它不需要 C++17,它要求您的标准库/编译器至少实现库基础 TS v2 的这一部分。您可以尝试一下,看看它是否有效,否则请查看您的编译器/标准库的文档,看看它是否有效
【解决方案2】:

在这种情况下,__LINE__ 宏扩展为 3

当然,因为您的函数声明是在第 3 行完成的,并且预处理器会从那里扩展它。

另一个宏而不是函数声明可以很好地解决问题(取自@Ejay's comment):

#define print() printf("hello %d\n", __LINE__)

查看工作示例here

【讨论】:

  • @Jarod42 完成了。
【解决方案3】:

您可以编写一个将__FILE____LINE__ 插入参数列表的宏:

// Note: this doesn't work with a 0-argument function. Supporting 0-arg functions
// is much harder to do; I'd recommend just having a separate macro like as follows
#define LOCATED(fn, ...) fn(__VA_ARGS__, __FILE__, __LINE__)

#define LOCATED0(fn) fn(__FILE__, __LINE__)

void print(char const* file_name, int line)
{
    printf("hello %s:%d\n", file_name, line);
}

int do_something(int value, char const* file_name, int line);

int main() {
    LOCATED0(print);
    LOCATED(do_something, 42);
}

再做一些工作,你可以让它在呼叫站点看起来更漂亮:

#define LOCATED(...) LOCATED_##__VA_ARGS__

void print(char const* file_name, int line)
{
    printf("hello %s:%d\n", file_name, line);
}
#define LOCATED_print() ::print(__FILE__, __LINE__)

int do_something(int value, char const* file_name, int line);
#define LOCATED_do_something(value) ::do_something(value, __FILE__, __LINE__)

int main() {
    LOCATED(print());
    LOCATED(do_something(42));
}

【讨论】:

  • 我看不出这与print(LOCATION)(我目前在我的代码中如何做)有什么不同,除了把它翻过来。
  • @pulp_user 你说得对,它并不比print(LOCATION)好,但它是一种替代方案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-03
  • 2012-02-29
相关资源
最近更新 更多