提问人:Ferenc Deak 提问时间:4/26/2023 最后编辑:DailyLearnerFerenc Deak 更新时间:4/27/2023 访问量:130
折叠表达式的“if constexpr”
`if constexpr` in fold expression
问:
我正在尝试在一个函数中制作一个折叠表达式,该函数使用来自字符串向量的一些值填充函数的传出参数。我的折叠表达是这样的:
((if constexpr (std::is_integral_v<Args>)
{
args = std::stoi(vec[index++]);
}
else if constexpr (std::is_same_v<Args, std::string>)
{
args = vec[index++];
}
else
{
throw std::invalid_argument("Unsupported argument type.");
}), ...);
但它无法编译,并显示奇怪的错误消息:
clang: error: expected expression
或
gcc: error: expected primary-expression before 'if'
(如 https://gcc.godbolt.org/z/xeq3j6oE7 所示)
有没有人对如何正确解决此问题有提示?
编辑
问题的完整上下文是这个简短的应用程序:
#include <vector>
#include <string>
#include <type_traits>
#include <iostream>
#include <stdexcept>
template <typename... Args>
void populateArgs(std::vector<std::string>& vec, Args&... args)
{
const size_t numArgs = sizeof...(Args);
if (vec.size() != numArgs)
{
throw std::invalid_argument("Number of arguments doesn't match the size of the vector.");
}
int index = 0;
((if constexpr (std::is_integral_v<Args>)
{
args = std::stoi(vec[index++]);
}
else if constexpr (std::is_same_v<Args, std::string>)
{
args = vec[index++];
}
else
{
throw std::invalid_argument("Unsupported argument type.");
}), ...);
}
int main()
{
std::vector<std::string> vec{ "1", "2", "3", "hello" };
short a;
int b;
long long c;
std::string d;
populateArgs(vec, a, b, c, d);
std::cout << "a = " << a << ", b = " << b << ", c = " << c << ", d = " << d << std::endl;
// Output: a = 1, b = 2, c = 3, d = hello
}
答:
6赞
HolyBlackCat
4/26/2023
#1
喜欢这个:
([&]{
// if constexpr ...
}(), ...);
这将创建一个 lambda 并立即调用它。
我记得这在 MSVC 上引起了一些问题。如果它不适合您,您可以尝试:
([&]<typename T>()
{
// Use `T` instead of `Args` here.
}.operator()<Args>(), ...);
或单独的模板函数。
评论
0赞
463035818_is_not_an_ai
4/26/2023
像这样 gcc.godbolt.org/z/o3feWz1aG
0赞
Ferenc Deak
4/26/2023
@HolyBlackCat介意添加一些解释为什么需要 lambda 的模糊性?谢谢!
1赞
463035818_is_not_an_ai
4/26/2023
@FerencDeak表达式都具有值。 是一个声明 en.cppreference.com/w/cpp/language/ifif ...
0赞
Ferenc Deak
4/26/2023
这很公平,谢谢!:D
0赞
HolyBlackCat
4/26/2023
@FerencDeak没什么大不了的。一个函数体只能包含一系列语句(例如 是一个语句)。 也是一个善意的声明。但是折叠表达式需要将表达式作为操作数,而不是操作数。if constexpr (...) {...}
expression;
if constexpr
1赞
fabian
4/27/2023
#2
if constexpr
恕我直言,这不是对类型进行“切换”的好方法。恕我直言,您最好创建函数模板的重载。
此外,我强烈建议导致编译器错误,以指示传递给 的参数无效。populateArgs
// set to 0 to use exception instead
#define DETECT_ERROR_AT_COMPILETIME 1
// set to 1 to simulate an invalid use of populateArgs
#define USE_INCORRECT_CALL 0
namespace impl // use a suitable namespace in case the functionality becomes part of a header file
{
template<class T>
constexpr bool AlwaysFalse = false;
template<class T>
void AssignFromConvertedString(T& lhs, std::string const& str)
{
#if DETECT_ERROR_AT_COMPILETIME
static_assert(AlwaysFalse<T>, "Unsupported argument type.");
#else
throw std::invalid_argument("Unsupported argument type.");
#endif
}
template<std::integral T>
void AssignFromConvertedString(T& lhs, std::string const& value)
{
lhs = std::stoi(value);
}
inline void AssignFromConvertedString(std::string& lhs, std::string const& value)
{
lhs = value;
}
}
template <typename... Args>
void populateArgs(std::vector<std::string>& vec, Args&... args)
{
const size_t numArgs = sizeof...(Args);
if (vec.size() != numArgs)
{
throw std::invalid_argument("Number of arguments doesn't match the size of the vector.");
}
size_t index = 0;
((impl::AssignFromConvertedString(args, vec[index++])), ...);
}
int main()
{
std::vector<std::string> vec{ "1", "2", "3", "hello" };
short a;
int b;
#if USE_INCORRECT_CALL
std::nullptr_t c;
#else
long long c;
#endif
std::string d;
populateArgs(vec, a, b, c, d);
std::cout << "a = " << a << ", b = " << b << ", c = " << c << ", d = " << d << std::endl;
// Output: a = 1, b = 2, c = 3, d = hello
}
评论