我想简单地使用unsigned(123)
和123u
,而不是123ul
和(unsigned long)(123)
。
#include <cstdint>
#include <variant>
using namespace std;
int main()
{
using var_t = variant<int64_t,uint64_t,double>;
var_t v1{1};
var_t v2{1ul};
var_t v3{1u}; //ERROR
// var_t v4{unsigned(1)}; //ERROR
var_t v5{uint64_t(1)};
}
实例
编译器输出
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:10:15: error: no matching function for call to 'std::variant<long int, long unsigned int, double>::variant(<brace-enclosed initializer list>)'
10 | var_t v3{1u}; //ERROR
| ^
In file included from main.cpp:2:
/usr/local/include/c++/10.2.0/variant:1402:2: note: candidate: 'template<long unsigned int _Np, class _Up, class ... _Args, class _Tp, class> constexpr std::variant<_Types>::variant(std::in_place_index_t<_Np>, std::initializer_list<_Up>, _Args&& ...) [with long unsigned int _Np = _Np; _Up = _Up; _Args = {_Args ...}; _Tp = _Tp; <template-parameter-2-5> = <template-parameter-1-5>; _Types = {long int, long unsigned int, double}]'
1402 | variant(in_place_index_t<_Np>, initializer_list<_Up> __il,
| ^~~~~~~
/usr/local/include/c++/10.2.0/variant:1402:2: note: template argument deduction/substitution failed:
main.cpp:10:15: note: mismatched types 'std::in_place_index_t<_Idx>' and 'unsigned int'
10 | var_t v3{1u}; //ERROR
| ^
In file included from main.cpp:2:
/usr/local/include/c++/10.2.0/variant:1391:2: note: candidate: 'template<long unsigned int _Np, class ... _Args, class _Tp, class> constexpr std::variant<_Types>::variant(std::in_place_index_t<_Np>, _Args&& ...) [with long unsigned int _Np = _Np; _Args = {_Args ...}; _Tp = _Tp; <template-parameter-2-4> = <template-parameter-1-4>; _Types = {long int, long unsigned int, double}]'
1391 | variant(in_place_index_t<_Np>, _Args&&... __args)
| ^~~~~~~
/usr/local/include/c++/10.2.0/variant:1391:2: note: template argument deduction/substitution failed:
main.cpp:10:15: note: mismatched types 'std::in_place_index_t<_Idx>' and 'unsigned int'
10 | var_t v3{1u}; //ERROR
| ^
In file included from main.cpp:2:
/usr/local/include/c++/10.2.0/variant:1381:2: note: candidate: 'template<class _Tp, class _Up, class ... _Args, class> constexpr std::variant<_Types>::variant(std::in_place_type_t<_Tp>, std::initializer_list<_Up>, _Args&& ...) [with _Tp = _Tp; _Up = _Up; _Args = {_Args ...}; <template-parameter-2-4> = <template-parameter-1-4>; _Types = {long int, long unsigned int, double}]'
1381 | variant(in_place_type_t<_Tp>, initializer_list<_Up> __il,
| ^~~~~~~
/usr/local/include/c++/10.2.0/variant:1381:2: note: template argument deduction/substitution failed:
main.cpp:10:15: note: mismatched types 'std::in_place_type_t<_Tp>' and 'unsigned int'
10 | var_t v3{1u}; //ERROR
| ^
In file included from main.cpp:2:
/usr/local/include/c++/10.2.0/variant:1371:2: note: candidate: 'template<class _Tp, class ... _Args, class> constexpr std::variant<_Types>::variant(std::in_place_type_t<_Tp>, _Args&& ...) [with _Tp = _Tp; _Args = {_Args ...}; <template-parameter-2-3> = <template-parameter-1-3>; _Types = {long int, long unsigned int, double}]'
1371 | variant(in_place_type_t<_Tp>, _Args&&... __args)
| ^~~~~~~
/usr/local/include/c++/10.2.0/variant:1371:2: note: template argument deduction/substitution failed:
main.cpp:10:15: note: mismatched types 'std::in_place_type_t<_Tp>' and 'unsigned int'
10 | var_t v3{1u}; //ERROR
| ^
In file included from main.cpp:2:
/usr/local/include/c++/10.2.0/variant:1361:2: note: candidate: 'template<class _Tp, class, class, class _Tj, class> constexpr std::variant<_Types>::variant(_Tp&&) [with _Tp = _Tp; <template-parameter-2-2> = <template-parameter-1-2>; <template-parameter-2-3> = <template-parameter-1-3>; _Tj = _Tj; <template-parameter-2-5> = <template-parameter-1-5>; _Types = {long int, long unsigned int, double}]'
1361 | variant(_Tp&& __t)
| ^~~~~~~
/usr/local/include/c++/10.2.0/variant:1361:2: note: template argument deduction/substitution failed:
/usr/local/include/c++/10.2.0/variant: In substitution of 'template<class ... _Types> template<class _Tp, class> using __accepted_type = std::variant<_Types>::__to_type<__accepted_index<_Tp> > [with _Tp = unsigned int&&; <template-parameter-2-2> = void; _Types = {long int, long unsigned int, double}]':
/usr/local/include/c++/10.2.0/variant:1357:9: required from here
/usr/local/include/c++/10.2.0/variant:1327:8: error: no type named 'type' in 'struct std::enable_if<false, void>'
1327 | using __accepted_type = __to_type<__accepted_index<_Tp>>;
| ^~~~~~~~~~~~~~~
/usr/local/include/c++/10.2.0/variant:1349:7: note: candidate: 'constexpr std::variant<_Types>::variant(std::variant<_Types>&&) [with _Types = {long int, long unsigned int, double}]'
1349 | variant(variant&&) = default;
| ^~~~~~~
/usr/local/include/c++/10.2.0/variant:1349:15: note: no known conversion for argument 1 from 'unsigned int' to 'std::variant<long int, long unsigned int, double>&&'
1349 | variant(variant&&) = default;
| ^~~~~~~~~
/usr/local/include/c++/10.2.0/variant:1348:7: note: candidate: 'constexpr std::variant<_Types>::variant(const std::variant<_Types>&) [with _Types = {long int, long unsigned int, double}]'
1348 | variant(const variant& __rhs) = default;
| ^~~~~~~
/usr/local/include/c++/10.2.0/variant:1348:30: note: no known conversion for argument 1 from 'unsigned int' to 'const std::variant<long int, long unsigned int, double>&'
1348 | variant(const variant& __rhs) = default;
| ~~~~~~~~~~~~~~~^~~~~
/usr/local/include/c++/10.2.0/variant:1347:7: note: candidate: 'constexpr std::variant<_Types>::variant() [with _Types = {long int, long unsigned int, double}]'
1347 | variant() = default;
| ^~~~~~~
/usr/local/include/c++/10.2.0/variant:1347:7: note: candidate expects 0 arguments, 1 provided
main.cpp:10:10: warning: unused variable 'v3' [-Wunused-variable]
10 | var_t v3{1u}; //ERROR
| ^~
我们为variant
制定的最后一条规则是,我们只考虑转换不窄化的替代方案,并且窄化确定考虑类型,而不是值。
除其他外:
- 浮点的整数总是在缩小
- signed到unsigned总是在缩小
- 如果有符号类型不能表示无符号类型的所有可能值,则unsigned到signed正在缩小
所以:
- 对于
v1
,源类型为int
,唯一的非窄化备选方案为int64_t
,并且选择了它 - 对于
v2
,源类型为unsigned long
。如果sizeof(int64_t) == sizeof(unsigned long)
,就像许多平台的情况一样,那么唯一不窄化的替代方案是uint64_t
,并选择它 - 对于
v3
,源类型为unsigned int
。如果int
是32位,则int64_t
和uint64_t
都是可行的选项,并且两者都不比另一个好。所以它是模棱两可的
对于这种事情,使用in_place_type
来明确选择您想要的替代方案要清楚得多,而不是要求读者在他们的头脑中进行过载解决。
答案取决于平台,但在我的平台(64位linux+gcc C++(上,您的结果非常合理。请注意,在以下所有结果中,转换为double
的排名低于积分晋升,因此它不参与。
// Below works, as 1 is signed, and can only be promoted to int64_t.
variant<int64_t,uint64_t,double> v1{1};
// Below works, as 1ul is exactly unsigned long (64 bit for me), and is exact match
variant<int64_t,uint64_t,double> v2{1ul};
// Below doesn't work, as 1u is unsigned int, and can be equally promoted to int64_t and uint64_t - thus ambiguity
variant<int64_t,uint64_t,double> v3{1u}; //ERROR
// Below doesn't work, for exactly the same reason as one above.
variant<int64_t,uint64_t,double> v4{unsigned(1)}; //ERROR
}
我发现了一个扩展std::variant:的优雅解决方案
#include <cstdint>
#include <variant>
using namespace std;
struct var_t : variant<int64_t,uint64_t,double> {
using variant<int64_t,uint64_t,double>::variant;
constexpr var_t(unsigned u) : variant(uint64_t(u)) {}
};
int main()
{
var_t v1{1};
var_t v2{1ul};
var_t v3{1u}; // VALID
var_t v4{unsigned(1)}; // VALID
var_t v5{uint64_t(1)};
}
实例
无需使用笨重的in_place_type
。当然它很有用,但在这种情况下没有。
感谢大家的关注