有没有办法从 `std::initializer_list` 创建用户定义的文字?
Is there a way to create a user-defined-literal from `std::initializer_list`?
就像主题中一样:有没有办法从 std::initializer_list
创建用户定义的文字?
我正在尝试做类似的事情:
template <typename T> inline
std::initializer_list<T> const & operator "" _lit(std::initializer_list<T> const & list)
{
return std::move(list); // I am not sure, but this line might cause undefined behavior... well I'll think about it latter...
}
int main()
{
{ 10, 20, 30, 40 }_lit // Error: identifier '_lit' is undefined;
return 0;
}
但编译器似乎不理解我正在尝试调用 operator""_lit({10, 20, 30, 40});
有什么办法可以解决它吗?
编辑:
对不起,原来这只是XY问题的另一个例子......
让我详细说明
我正在尝试 "expand" 当前的 C++ 语法(这是一个有趣的小项目...)
主要思想是简化这个:
if ((val_1 == value) && (val_2 == value) && (val_3 == value)) { /* ... */ }
进入以下线路:
if (std::initializer_list<T>{val_1, val_2, val_3} == value)
ofc 我正在提供额外的操作员:
template <typename T> inline
bool operator==(std::initializer_list<T> const & list, T const & ref)
{
for (auto const & element : list)
{
if (element == ref) { /* Do nothing. */ }
else
{
return false;
}
}
return true;
}
一切都会很好,但我不喜欢在花括号前键入 std::initializer_list<T>
的需要...否则,编译器会选择 operator==()
的默认版本,我得到编译错误...
文字来到这里是为了将 if (std::initializer_list<T>{val_1, val_2, val_3} == value)
更改为 if ({val_1, val_2, val_3}_lit == value)
您不能为 std::initializer_list
创建用户定义的文字。幸运的是,尽管 C++17 提供了一个非常酷的新工具来帮助我们。 Class template argument deduction 允许我们只使用 class 模板的名称,编译器会找出模板参数需要的内容,因此我们不必指定它们。这意味着您可以利用 std::array
并且您的代码将变为
template<typename T, std::size_t N>
bool operator==(std::array<T, N> const & list, T const & ref)
{
for(auto const& e : list)
if (e != ref)
return false;
return true;
}
int main()
{
using std::array;
if (array{4,4,4,4,4} == 4)
std::cout << "all 4";
}
除了using语句之外,它只是_lit
和array
之间的一个额外字符
来自评论:
@NathanOliver I am trying to "expand" current C++ syntax (it's a fun
little project...) The main idea is to simplify this: if ((val_1 ==
value) && (val_2 == value) && (val_3 == value)) into this: if
(std::initializer_list{val_1, val_2, val_3} == value) (ofc with an
overloaded operator: bool operator==(std::initializer_list const &
list, T const & ref))... I want to ommit the part in which i need to
type std::initializer_list and i figured out that i can change it
into a custom-literal
看来您需要这样的东西:
template<typename T>
bool allEqualTo(T a, T b)
{
return a == b;
}
template<typename T, typename... TArgs>
bool allEqualTo(T a, T b, TArgs... args)
{
return allEqualTo(a, b) && allEqualTo(a, args...);
}
if (allEqualTo(value, val_1, val_2, val_3)) {
....
}
如果你使用范围库,你可以只使用 all_of
:
// Using Range-v3: https://ericniebler.github.io/range-v3/index.html
if (ranges::v3::all_of({val_1, val_2, val_3},
[value](auto const& other) { return value == other; })) {
// ...
}
您可以使用助手来进一步简化它:
// Note: Prior to C++17, this could lead to ODR violations.
// After C++17, this will be an inline variable, thus this is fine.
// If using in C++14 or before, write std::equal_to<>{} instead of std::equal_to{}.
constexpr auto equal_to = boost::hof::partial(std::equal_to{});
// ...
if (ranges::v3::all_of({val1, val_2, val_3}, equal_to(value))) {
// ...
}
template<class T, std::size_t N>
struct any_of:std::array<T, N> {
#define MAKE_OPERATOR( OPERATOR ) \
template<class U, \
std::enable_if_t< std::is_same<void, std::void_t< \
decltype( std::declval<T const&>() == std::declval<U const&>() ) \
>>{}, bool> =true \
> \
friend bool operator OPERATOR ( any_of const& lhs, U const& rhs) { \
return std::any_of( \
lhs.begin(), lhs.end(), \
[&](auto&& lhs){ return lhs OPERATOR rhs; } \
); \
} \
template<class U, \
std::enable_if_t< std::is_same<void, std::void_t< \
decltype( std::declval<U const&>() == std::declval<T const&>() ) \
>>{} && !std::is_same< U, any_of >{} , bool> =true \
> \
friend bool operator OPERATOR ( U const& lhs, any_of const& rhs) { \
return std::any_of( \
rhs.begin(), rhs.end(), \
[&](auto&& rhs){ return lhs OPERATOR rhs; } \
); \
}
MAKE_OPERATOR(==)
MAKE_OPERATOR(!=)
MAKE_OPERATOR(<)
MAKE_OPERATOR(<=)
MAKE_OPERATOR(>=)
MAKE_OPERATOR(>)
#undef MAKE_OPERATOR
explicit any_of( std::array<T, N> arr):std::array<T, N>(std::move(arr)) {}
template<class...Ts>
explicit any_of( T t, Ts... ts ):std::array<T, N>{ std::move(t), std::move(ts)... } {}
any_of( any_of const& )=delete;
any_of& operator=( any_of const& )=delete;
any_of()=delete;
};
template<class T, std::size_t N>
any_of(T(&)[N]) -> any_of<T,N>;
template<class T, class...Ts>
any_of(T, Ts...) -> any_of<T, 1+sizeof...(Ts)>;
测试代码:
if (any_of{1,2,3} == 2) {
std::cout << "2 is there\n";
}
if (! (any_of{1,2,3} == 7) ){
std::cout << "7 is not there\n";
}
if (any_of{1,2,3} == any_of{5,6,1}) {
std::cout << "overlap!\n";
}
if (!(any_of{1,2,3} == any_of{5,6,7})) {
std::cout << "no overlap!\n";
}
c++17 编译器中的输出:
2 is there
7 is not there
overlap!
no overlap!
支持各种比较运算符。
十字型双any_of,喜欢:
any_of{1,2,3} == any_of{3.14, 5.7, 1.0}
将无法编译,因为 ==
和 any_of
都有效。
就像主题中一样:有没有办法从 std::initializer_list
创建用户定义的文字?
我正在尝试做类似的事情:
template <typename T> inline
std::initializer_list<T> const & operator "" _lit(std::initializer_list<T> const & list)
{
return std::move(list); // I am not sure, but this line might cause undefined behavior... well I'll think about it latter...
}
int main()
{
{ 10, 20, 30, 40 }_lit // Error: identifier '_lit' is undefined;
return 0;
}
但编译器似乎不理解我正在尝试调用 operator""_lit({10, 20, 30, 40});
有什么办法可以解决它吗?
编辑:
对不起,原来这只是XY问题的另一个例子......
让我详细说明
我正在尝试 "expand" 当前的 C++ 语法(这是一个有趣的小项目...)
主要思想是简化这个:
if ((val_1 == value) && (val_2 == value) && (val_3 == value)) { /* ... */ }
进入以下线路:
if (std::initializer_list<T>{val_1, val_2, val_3} == value)
ofc 我正在提供额外的操作员:
template <typename T> inline
bool operator==(std::initializer_list<T> const & list, T const & ref)
{
for (auto const & element : list)
{
if (element == ref) { /* Do nothing. */ }
else
{
return false;
}
}
return true;
}
一切都会很好,但我不喜欢在花括号前键入 std::initializer_list<T>
的需要...否则,编译器会选择 operator==()
的默认版本,我得到编译错误...
文字来到这里是为了将 if (std::initializer_list<T>{val_1, val_2, val_3} == value)
更改为 if ({val_1, val_2, val_3}_lit == value)
您不能为 std::initializer_list
创建用户定义的文字。幸运的是,尽管 C++17 提供了一个非常酷的新工具来帮助我们。 Class template argument deduction 允许我们只使用 class 模板的名称,编译器会找出模板参数需要的内容,因此我们不必指定它们。这意味着您可以利用 std::array
并且您的代码将变为
template<typename T, std::size_t N>
bool operator==(std::array<T, N> const & list, T const & ref)
{
for(auto const& e : list)
if (e != ref)
return false;
return true;
}
int main()
{
using std::array;
if (array{4,4,4,4,4} == 4)
std::cout << "all 4";
}
除了using语句之外,它只是_lit
和array
来自评论:
@NathanOliver I am trying to "expand" current C++ syntax (it's a fun little project...) The main idea is to simplify this: if ((val_1 == value) && (val_2 == value) && (val_3 == value)) into this: if (std::initializer_list{val_1, val_2, val_3} == value) (ofc with an overloaded operator: bool operator==(std::initializer_list const & list, T const & ref))... I want to ommit the part in which i need to type std::initializer_list and i figured out that i can change it into a custom-literal
看来您需要这样的东西:
template<typename T>
bool allEqualTo(T a, T b)
{
return a == b;
}
template<typename T, typename... TArgs>
bool allEqualTo(T a, T b, TArgs... args)
{
return allEqualTo(a, b) && allEqualTo(a, args...);
}
if (allEqualTo(value, val_1, val_2, val_3)) {
....
}
如果你使用范围库,你可以只使用 all_of
:
// Using Range-v3: https://ericniebler.github.io/range-v3/index.html
if (ranges::v3::all_of({val_1, val_2, val_3},
[value](auto const& other) { return value == other; })) {
// ...
}
您可以使用助手来进一步简化它:
// Note: Prior to C++17, this could lead to ODR violations.
// After C++17, this will be an inline variable, thus this is fine.
// If using in C++14 or before, write std::equal_to<>{} instead of std::equal_to{}.
constexpr auto equal_to = boost::hof::partial(std::equal_to{});
// ...
if (ranges::v3::all_of({val1, val_2, val_3}, equal_to(value))) {
// ...
}
template<class T, std::size_t N>
struct any_of:std::array<T, N> {
#define MAKE_OPERATOR( OPERATOR ) \
template<class U, \
std::enable_if_t< std::is_same<void, std::void_t< \
decltype( std::declval<T const&>() == std::declval<U const&>() ) \
>>{}, bool> =true \
> \
friend bool operator OPERATOR ( any_of const& lhs, U const& rhs) { \
return std::any_of( \
lhs.begin(), lhs.end(), \
[&](auto&& lhs){ return lhs OPERATOR rhs; } \
); \
} \
template<class U, \
std::enable_if_t< std::is_same<void, std::void_t< \
decltype( std::declval<U const&>() == std::declval<T const&>() ) \
>>{} && !std::is_same< U, any_of >{} , bool> =true \
> \
friend bool operator OPERATOR ( U const& lhs, any_of const& rhs) { \
return std::any_of( \
rhs.begin(), rhs.end(), \
[&](auto&& rhs){ return lhs OPERATOR rhs; } \
); \
}
MAKE_OPERATOR(==)
MAKE_OPERATOR(!=)
MAKE_OPERATOR(<)
MAKE_OPERATOR(<=)
MAKE_OPERATOR(>=)
MAKE_OPERATOR(>)
#undef MAKE_OPERATOR
explicit any_of( std::array<T, N> arr):std::array<T, N>(std::move(arr)) {}
template<class...Ts>
explicit any_of( T t, Ts... ts ):std::array<T, N>{ std::move(t), std::move(ts)... } {}
any_of( any_of const& )=delete;
any_of& operator=( any_of const& )=delete;
any_of()=delete;
};
template<class T, std::size_t N>
any_of(T(&)[N]) -> any_of<T,N>;
template<class T, class...Ts>
any_of(T, Ts...) -> any_of<T, 1+sizeof...(Ts)>;
测试代码:
if (any_of{1,2,3} == 2) {
std::cout << "2 is there\n";
}
if (! (any_of{1,2,3} == 7) ){
std::cout << "7 is not there\n";
}
if (any_of{1,2,3} == any_of{5,6,1}) {
std::cout << "overlap!\n";
}
if (!(any_of{1,2,3} == any_of{5,6,7})) {
std::cout << "no overlap!\n";
}
c++17 编译器中的输出:
2 is there 7 is not there overlap! no overlap!
支持各种比较运算符。
十字型双any_of,喜欢:
any_of{1,2,3} == any_of{3.14, 5.7, 1.0}
将无法编译,因为 ==
和 any_of
都有效。