这段代码可以在g ++(coliru)中很好地编译,但是在MSVC(Godbolt和我的VS2017)中却不能。
#include <type_traits>
#include <iostream>
template<class T> void f(){
constexpr bool b=std::is_same_v<T,int>; //#1
auto func_x=[&](){
if constexpr(b){ //#error
}else{
}
};
func_x();
}
int main(){
f<int>();
}
Run Code Online (Sandbox Code Playgroud)
(6):错误C2131:表达式未求值为常数
(6):注意:失败是由于在其生命周期之外读取变量导致的
(6):注意:请参见'this'的用法
哪一个(g ++或MSVC)错了?“ 请参阅'this'的用法 ”
是什么??this
在保留编译时保证的同时如何解决呢?
在我的真实情况下,b (#1)一个复杂的语句取决于其他一些constexpr变量。
GCC9已经实施std::is_constant_evaluated.我玩了一点,我意识到这有点棘手.这是我的测试:
constexpr int Fn1()
{
if constexpr (std::is_constant_evaluated())
return 0;
else
return 1;
}
constexpr int Fn2()
{
if (std::is_constant_evaluated())
return 0;
else
return 1;
}
int main()
{
constexpr int test1 = Fn1(); // Evaluates to 0
int test2 = Fn1(); // Evaluates to 0
int const test3 = Fn1(); // Evaluates to 0
constexpr int test4 = Fn2(); // Evaluates to 0
int test5 = Fn2(); // Evaluates to 1
int const test6 = Fn2(); // …Run Code Online (Sandbox Code Playgroud) 以下代码使用g ++ 7.3.0成功编译,无法使用clang ++ 6.0.0进行编译(编译标志为-std=c++17 -Wall -Wextra -Werror -pedantic-errors):
auto foo = [](auto, auto... tail) {
if constexpr (sizeof...(tail) > 0)
{
return foo(tail...);
}
else
{
return 42;
}
};
int main()
{
}
Run Code Online (Sandbox Code Playgroud)
clang ++编译错误信息:
错误:使用推导类型'auto'声明的变量'foo'不能出现在自己的初始化程序中
Run Code Online (Sandbox Code Playgroud)return foo(tail...);
在这种情况下,符合标准的行为是什么?
我在 GCC 10 中使用 c++20 consteval 并编写了这段代码
#include <optional>
#include <tuple>
#include <iostream>
template <std::size_t N, typename Predicate, typename Tuple>
consteval std::optional<std::size_t> find_if_impl(Predicate&& pred,
Tuple&& t) noexcept {
constexpr std::size_t I = std::tuple_size_v<std::decay_t<decltype(t)>> - N;
if constexpr (N == 0u) {
return std::nullopt;
} else {
return pred(std::get<I>(t))
? std::make_optional(I)
: find_if_impl<N - 1u>(std::forward<decltype(pred)>(pred),
std::forward<decltype(t)>(t));
}
}
template <typename Predicate, typename Tuple>
consteval std::optional<std::size_t> find_if(Predicate&& pred,
Tuple&& t) noexcept {
return find_if_impl<std::tuple_size_v<std::decay_t<decltype(t)>>>(
std::forward<decltype(pred)>(pred), std::forward<decltype(t)>(t));
}
constexpr auto is_integral = [](auto&& …Run Code Online (Sandbox Code Playgroud) if constexpr是在C++程序中摆脱预处理器的重要一步.但它仅适用于函数 - 如下例所示:
enum class OS
{
Linux,
MacOs,
MsWindows,
Unknown
};
#if defined(__APPLE__)
constexpr OS os = OS::MacOs;
#elif defined(__MINGW32__)
constexpr OS os = OS::MsWindows;
#elif defined(__linux__)
constexpr OS os = OS::Linux;
#else
constexpr OS os = OS::Unknown;
#endif
void printSystem()
{
if constexpr (os == OS::Linux)
{
std::cout << "Linux";
}
else if constexpr (os == OS::MacOs)
{
std::cout << "MacOS";
}
else if constexpr (os == OS::MsWindows)
{
std::cout << "MS Windows";
}
else
{ …Run Code Online (Sandbox Code Playgroud) 在我看来,在MSVC(版本15.7.3)中评估另一个constexpr-if语句的废弃分支内的constexpr-if语句.
请考虑以下代码:
#include <tuple>
#include <type_traits>
template <size_t I>
int test() {
if constexpr(I != 0) {
return 0;
}
else { // This branch is discarded, but it seems that the constexpr-if below is still evaulated?
if constexpr(std::is_same_v<int, std::tuple_element_t<I, std::tuple<int>>>) { // some constexpr check that is valid only when I == 0
return 1;
}
else {
return 2;
}
}
}
int main() {
test<1>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码无法在MSVC中编译,因为std::tuple_element_t当I超过元组的边界时,静态断言将失败.这表明,不管怎样,废弃分支中的代码也会被评估,即使它依赖于模板参数I.
我在模板化的lambda中遇到"if constexpr"的问题.为了论证,让我们忽略我是如何到达那里的,但我有一个结构foo,它以某种方式定义,产生如下内容:
template<bool condition>
struct foo {
int a;
// Only contains b if condition is true
int b;
}
Run Code Online (Sandbox Code Playgroud)
现在我可以定义一个模板函数thtemplate
template<bool condition>
void print_fun(foo & obj) {
/* Do something with obj.a */
if constexpr(condition)
/* Do something with obj.b */
};
Run Code Online (Sandbox Code Playgroud)
实例化这个功能,并使用它会编译,如果constexpr参数foo是一样的一个print_fun,即
constexpr bool no = false;
foo<no> obj = {};
print_fun<no>(obj);
Run Code Online (Sandbox Code Playgroud)
这会编译,因为假分支在模板化实体内被丢弃,因此在print_fun中使用obj.b没有问题.
但是,如果我定义一个类似的lambda表达式如下:
template<bool condition>
auto print_lambda = [](foo & obj) {
/* Do something with obj.a */
if constexpr(condition)
/* Do something …Run Code Online (Sandbox Code Playgroud) 我正在寻找的是:我有一个模板化的类,如果该类具有所需的函数,则想调用一个函数,例如:
template<class T> do_something() {
if constexpr (std::is_member_function_pointer<decltype(&T::x)>::value) {
this->_t->x(); // _t is type of T*
}
}
Run Code Online (Sandbox Code Playgroud)
发生的情况:如果T不带功能,则编译器不会编译。小例子:
#include <type_traits>
#include <iostream>
class Foo {
public:
void x() { }
};
class Bar { };
int main() {
std::cout << "Foo = " << std::is_member_function_pointer<decltype(&Foo::x)>::value << std::endl;
std::cout << "Bar = " << std::is_member_function_pointer<decltype(&Bar::x)>::value << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译器说:
is_member_function_pointer.cpp:17:69: error: no member named 'x' in 'Bar'; did you mean 'Foo::x'?
std::cout << "Bar …Run Code Online (Sandbox Code Playgroud) 目前,我正在学习 C++,并决定从 C++20 开始。然而,这些代码让我发疯,因为我认为结果没有任何意义。
以下代码将Valid array.打印句子。我上面的意思是,这是不对的。它根本不应该打印句子,因为我在参数中插入的类型与概念不匹配。
在 VS2022 Preview 3 和具有最新 GCC 和 C++2A(GNU) 参数的在线编译器上进行测试,生成了相同的结果。
#include <array>
#include <cstdio>
#include <iostream>
#include <type_traits>
using namespace std;
template<typename A> concept ProperArray = requires(A array)
{
{array.max_size() >= 2U};
{std::is_arithmetic_v<typename A::value_type> == true};
};
int main()
{
constexpr bool b = ProperArray<array<std::string, 1>>;
if constexpr (b)
cout << "Valid array." << endl;
std::cout << "Hello, Wandbox!" << std::endl;
}
Run Code Online (Sandbox Code Playgroud) 我试图以if constexpr下列方式使用:
template<template <typename First, typename Second> class Trait,
typename First, typename Second, typename... Rest>
constexpr bool binaryTraitAre_impl()
{
if constexpr (sizeof... (Rest) == 0)
{
return Trait<First, Second>{}();
}
return Trait<First, Second>{}() and binaryTraitAre_impl<Trait, Rest...>();
}
Run Code Online (Sandbox Code Playgroud)
用例示例:
static_assert(binaryTraitAre_impl<std::is_convertible,
int, int&,
int*, void*>());
Run Code Online (Sandbox Code Playgroud)
但这无法编译
error: no matching function for call to 'binaryTraitAre_impl'
return Trait<First, Second>{}() and binaryTraitAre_impl<Trait, Rest...>();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
prog.cc: In instantiation of 'constexpr bool binaryTraitAre_impl() [with Trait = std::is_convertible; First = int*; Second …Run Code Online (Sandbox Code Playgroud) c++ ×10
if-constexpr ×10
c++17 ×6
c++20 ×3
lambda ×3
templates ×2
c++-concepts ×1
class ×1
constexpr ×1
nested ×1
type-traits ×1