我正在尝试使用C++ 17 if constexpr
进行条件编译,但它的行为不符合我的期望。
例如,对于下面的代码,C++仍将编译由X2
宏定义的代码,
#include <map>
#include <string>
#include <iostream>
#include <type_traits>
#define X1 pp("x")
#define X2 pp("x", "x")
void pp(const std::string str)
{
std::cout << str << std::endl;
}
int main()
{
std::map<std::string, int> map;
if constexpr (std::is_null_pointer_v<decltype(map)>)
X2;
else
X1;
}
并显示以下错误消息:1.c:6:23: error: too many arguments to function ‘void pp(std::__cxx11::string)’
#define X2 pp("x", "x")
^
1.c:18:3: note: in expansion of macro ‘X2’
X2;
^~
如何跳过X2的编译?
最佳答案
模板之外是不可能的!
从cppreference.com
Outside a template, a discarded statement is fully checked.
if constexpr
is not a substitute for the#if
preprocessing directive:void f() { if constexpr(false) { int i = 0; int *p = i; // Error even though in discarded statement } }
Any idea how to skip compilation of X2?
一种选择是为此提供模板功能。
template<typename T>
void test()
{
if constexpr (std::is_null_pointer_v<T>)
X2;
else
X1;
}
int main()
{
std::map<std::string, int> map;
test<decltype(map)>(); // now chooses the X1
}
感谢@HolyBlackCat和@MSalters。如他们所指出的,上面的解决方案是格式错误的NDR (因此,使用MSVC compiler进行编译没有任何意义,另一方面通过提供一些编译器错误GCC and clang at least catch this)
在@HolyBlackCat中已详细说明,
回答!
因此,我们可以跳过 X2 的编译吗?
不幸的是,按照您的代码否!
preprocessor将在编译翻译单元之前执行。
因此,无法将类型信息(即
decltype(map)
)提供给#if
指令。因此,对于您的情况,没有其他方法。
这个帖子的好教训:
和
constexpr if
混合。 如果可能的话,编译器!
我建议对您的情况有一个
PP
(当然还有许多其他方法)的函数重载,通过它可以得到格式正确的代码:See a demo。
#include <string>
#include <iostream>
#include <type_traits>
#include <map>
void pp(const std::string& str)
{
std::cout << str << std::endl;
}
template<typename... T> void pp(const T&... args)
{
// do something with args!
}
template<typename T>
constexpr void test()
{
if constexpr (std::is_null_pointer_v<T>)
pp("x", "x"); // call with args
else
pp("x"); // call with string
}
关于c++ - 如果constexpr失败,为什么会这样使用C++ 17?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63046397/