【发布时间】:2018-04-06 07:48:00
【问题描述】:
我正在尝试编写一个实用程序,该实用程序根据T 是否为聚合类型来调用new T{...} 或new T(...)。到目前为止,我所达到的内容如下。请注意,由于this issue,我使用的是宏而不是函数模板。
#define MAKE(p, T, ...) \
T* p; \
if constexpr (::std::is_aggregate_v<T>) { \
p = new T{__VA_ARGS__}; \
} \
else { \
p = new T(__VA_ARGS__); \
}
我尝试在 gcc 7.2.0 上测试它
struct pr_t {
int a, b;
};
int main() {
MAKE(p, pr_t, 1, 2);
}
随后出现以下错误 (live)。
prog.cc: In function 'int main()':
prog.cc:9:26: error: new initializer expression list treated as compound expression [-fpermissive]
p = new T(__VA_ARGS__); \
^
prog.cc:17:3: note: in expansion of macro 'MAKE'
MAKE(p, pr_t, 1, 2);
^~~~
prog.cc:9:26: warning: left operand of comma operator has no effect [-Wunused-value]
p = new T(__VA_ARGS__); \
^
prog.cc:17:3: note: in expansion of macro 'MAKE'
MAKE(p, pr_t, 1, 2);
^~~~
prog.cc:9:26: error: no matching function for call to 'pr_t::pr_t(int)'
p = new T(__VA_ARGS__); \
^
prog.cc:17:3: note: in expansion of macro 'MAKE'
MAKE(p, pr_t, 1, 2);
^~~~
prog.cc:12:8: note: candidate: pr_t::pr_t()
struct pr_t {
^~~~
prog.cc:12:8: note: candidate expects 0 arguments, 1 provided
prog.cc:12:8: note: candidate: constexpr pr_t::pr_t(const pr_t&)
prog.cc:12:8: note: no known conversion for argument 1 from 'int' to 'const pr_t&'
prog.cc:12:8: note: candidate: constexpr pr_t::pr_t(pr_t&&)
prog.cc:12:8: note: no known conversion for argument 1 from 'int' to 'pr_t&&'
编译器发现p = new T(__VA_ARGS__); 有问题。但是当::std::is_aggregate_v<T>为真时,不应该根本不考虑吗?
请注意,使用 if constexpr 和放置 new 的类似模式已经奏效。引用自cppref 示例。
template<class T, class... Args>
T* construct(T* p, Args&&... args) {
if constexpr(std::is_aggregate_v<T>) {
return ::new (static_cast<void*>(p)) T{std::forward<Args>(args)...};
}
else {
return ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
}
}
我猜非放置版本有什么特别之处?
【问题讨论】:
-
你为什么尝试在 C++ 中使用预处理器宏?如果您的 constexpr if 代码有效,请忘记所有宏的内容。
-
@Klaus 我已经更新了这个问题。我确实有理由不使用函数模板。
-
哎呀,锤了。问题的症结等同于另一个问题(在模板外使用
if constexpr),但也许应该在此处的答案中建立联系。 -
@Quentin 我已将其添加到我的答案中。
标签: c++ c++17 constexpr if-constexpr new-expression