区分值模板 class 和左值模板 class 的正确特化是什么?
What is the correct specialization for distinguishing between value template class and lvalue template class?
我需要进行模板专业化,以区分具有(仅)值参数的模板 class,如下所示:
template<auto ... __vz>
struct values{};
和一个模板 class 具有(仅)如下参考参数:
template<auto& ... __lvz>
struct lvalues{};
但是我没有成功进行以下专业化:
template<typename>
struct is_values{
static constexpr bool value = false;
};
template<template<auto ...>class __m, auto ... __vz>
struct is_values<__m<__vz ...> >{
static constexpr bool value = true;
};
template<typename>
struct is_lvalues{
static constexpr bool value = false;
};
template<template<auto& ...>class __m, auto& ... __vz>
struct is_lvalues<__m<__vz ...> >{
static constexpr bool value = true;
};
当他们进行如下测试时:
const int a = 1;
const int b = 2;
const int c = 3;
int main()
{
std::cout << is_values<lvalues<a,b,c> >::value <<std::endl; // wrong result
std::cout << is_lvalues<values<1,2,3> >::value <<std::endl; // causes error
}
其中一个给出了错误的结果,一个给出了以下错误:
test.cpp: In instantiation of ‘struct is_lvalues<values<1, 2, 3> >’:
test.cpp:51:41: required from here
test.cpp:32:34: error: initializing ‘int&’ with ‘int’ in converted constant expression does not bind directly
32 | struct is_lvalues<__m<__vz ...> >{
| ^
test.cpp:32:34: error: could not convert ‘1’ from ‘int’ to ‘int&’
test.cpp:32:34: error: initializing ‘int&’ with ‘int’ in converted constant expression does not bind directly
test.cpp:32:34: error: could not convert ‘2’ from ‘int’ to ‘int&’
test.cpp:32:34: error: initializing ‘int&’ with ‘int’ in converted constant expression does not bind directly
test.cpp:32:34: error: could not convert ‘3’ from ‘int’ to ‘int&’
test.cpp:33:24: error: initializing ‘int&’ with ‘int’ in converted constant expression does not bind directly
33 | static constexpr bool value = true;
| ^~~~~
test.cpp:33:24: error: could not convert ‘1’ from ‘int’ to ‘int&’
test.cpp:33:24: error: initializing ‘int&’ with ‘int’ in converted constant expression does not bind directly
test.cpp:33:24: error: could not convert ‘2’ from ‘int’ to ‘int&’
test.cpp:33:24: error: initializing ‘int&’ with ‘int’ in converted constant expression does not bind directly
test.cpp:33:24: error: could not convert ‘3’ from ‘int’ to ‘int&’
test.cpp: In function ‘int main()’:
test.cpp:51:43: error: ‘value’ is not a member of ‘is_lvalues<values<1, 2, 3> >’
51 | std::cout << is_lvalues<values<1,2,3> >::value <<std::endl; // causes error
| ^~~~~
make: *** [src/subdir.mk:20: src/test.o] Error 1
"make all" terminated with exit code 2. Build might be incomplete.
12:14:37 Build Failed. 14 errors, 0 warnings. (took 677ms)
到目前为止,我只在以下专业上取得了成功:
template<auto ... __vz>
struct is_values<values<__vz ...> >{
static constexpr bool value = true;
};
template<auto& ... __vz>
struct is_lvalues<lvalues<__vz ...> >{
static constexpr bool value = true;
};
但这些并不是我们想要的,因为它们只检测由 values
和 lvalues
产生的类型,而不是任何其他具有不同名称的类似模板。
那么什么是正确的专业化?
如果您要为 types 解决此问题,您可以使用
std::is_lvalue_reference
为单一类型执行此操作。由于您似乎使用的是 C++17,因此您可以使用折叠表达式将其应用于参数包:
template <typename... Ts>
using are_types_lvalues = std::integral_constant<bool, (std::is_lvalue_reference_v<Ts> && ...)>;
template <typename... Ts>
using are_types_values = std::integral_constant<bool, !(std::is_reference_v<Ts> || ...)>;
如果你可以测试类型,你可以只使用 decltype
来获取 non-type 参数的类型,而不用担心强制参数绑定到 auto
或 auto&
...
template<typename>
struct are_values : std::false_type {};
template<template<auto ...>class __m, auto ... __vz>
struct are_values<__m<__vz ...>> : std::integral_constant<bool, !(std::is_reference_v<decltype(__vz)> || ...)> {};
template<typename>
struct are_lvalues : std::false_type {};
template<template<auto ...>class __m, auto ... __vz>
struct are_lvalues<__m<__vz ...>> : std::integral_constant<bool, (std::is_lvalue_reference_v<decltype(__vz)> && ...)> {};
用法:
template<auto... __vz>
struct values{};
template<auto& ... __lvz>
struct lvalues{};
const int a = 1;
const int b = 2;
const int c = 3;
static_assert(are_values<values<1,2,3>>::value, "");
static_assert(!are_values<lvalues<a,b,c>>::value, "");
static_assert(!are_lvalues<values<1,2,3>>::value, "");
static_assert(are_lvalues<lvalues<a,b,c>>::value, "");
我需要进行模板专业化,以区分具有(仅)值参数的模板 class,如下所示:
template<auto ... __vz>
struct values{};
和一个模板 class 具有(仅)如下参考参数:
template<auto& ... __lvz>
struct lvalues{};
但是我没有成功进行以下专业化:
template<typename>
struct is_values{
static constexpr bool value = false;
};
template<template<auto ...>class __m, auto ... __vz>
struct is_values<__m<__vz ...> >{
static constexpr bool value = true;
};
template<typename>
struct is_lvalues{
static constexpr bool value = false;
};
template<template<auto& ...>class __m, auto& ... __vz>
struct is_lvalues<__m<__vz ...> >{
static constexpr bool value = true;
};
当他们进行如下测试时:
const int a = 1;
const int b = 2;
const int c = 3;
int main()
{
std::cout << is_values<lvalues<a,b,c> >::value <<std::endl; // wrong result
std::cout << is_lvalues<values<1,2,3> >::value <<std::endl; // causes error
}
其中一个给出了错误的结果,一个给出了以下错误:
test.cpp: In instantiation of ‘struct is_lvalues<values<1, 2, 3> >’:
test.cpp:51:41: required from here
test.cpp:32:34: error: initializing ‘int&’ with ‘int’ in converted constant expression does not bind directly
32 | struct is_lvalues<__m<__vz ...> >{
| ^
test.cpp:32:34: error: could not convert ‘1’ from ‘int’ to ‘int&’
test.cpp:32:34: error: initializing ‘int&’ with ‘int’ in converted constant expression does not bind directly
test.cpp:32:34: error: could not convert ‘2’ from ‘int’ to ‘int&’
test.cpp:32:34: error: initializing ‘int&’ with ‘int’ in converted constant expression does not bind directly
test.cpp:32:34: error: could not convert ‘3’ from ‘int’ to ‘int&’
test.cpp:33:24: error: initializing ‘int&’ with ‘int’ in converted constant expression does not bind directly
33 | static constexpr bool value = true;
| ^~~~~
test.cpp:33:24: error: could not convert ‘1’ from ‘int’ to ‘int&’
test.cpp:33:24: error: initializing ‘int&’ with ‘int’ in converted constant expression does not bind directly
test.cpp:33:24: error: could not convert ‘2’ from ‘int’ to ‘int&’
test.cpp:33:24: error: initializing ‘int&’ with ‘int’ in converted constant expression does not bind directly
test.cpp:33:24: error: could not convert ‘3’ from ‘int’ to ‘int&’
test.cpp: In function ‘int main()’:
test.cpp:51:43: error: ‘value’ is not a member of ‘is_lvalues<values<1, 2, 3> >’
51 | std::cout << is_lvalues<values<1,2,3> >::value <<std::endl; // causes error
| ^~~~~
make: *** [src/subdir.mk:20: src/test.o] Error 1
"make all" terminated with exit code 2. Build might be incomplete.
12:14:37 Build Failed. 14 errors, 0 warnings. (took 677ms)
到目前为止,我只在以下专业上取得了成功:
template<auto ... __vz>
struct is_values<values<__vz ...> >{
static constexpr bool value = true;
};
template<auto& ... __vz>
struct is_lvalues<lvalues<__vz ...> >{
static constexpr bool value = true;
};
但这些并不是我们想要的,因为它们只检测由 values
和 lvalues
产生的类型,而不是任何其他具有不同名称的类似模板。
那么什么是正确的专业化?
如果您要为 types 解决此问题,您可以使用
std::is_lvalue_reference
为单一类型执行此操作。由于您似乎使用的是 C++17,因此您可以使用折叠表达式将其应用于参数包:
template <typename... Ts>
using are_types_lvalues = std::integral_constant<bool, (std::is_lvalue_reference_v<Ts> && ...)>;
template <typename... Ts>
using are_types_values = std::integral_constant<bool, !(std::is_reference_v<Ts> || ...)>;
如果你可以测试类型,你可以只使用 decltype
来获取 non-type 参数的类型,而不用担心强制参数绑定到 auto
或 auto&
...
template<typename>
struct are_values : std::false_type {};
template<template<auto ...>class __m, auto ... __vz>
struct are_values<__m<__vz ...>> : std::integral_constant<bool, !(std::is_reference_v<decltype(__vz)> || ...)> {};
template<typename>
struct are_lvalues : std::false_type {};
template<template<auto ...>class __m, auto ... __vz>
struct are_lvalues<__m<__vz ...>> : std::integral_constant<bool, (std::is_lvalue_reference_v<decltype(__vz)> && ...)> {};
用法:
template<auto... __vz>
struct values{};
template<auto& ... __lvz>
struct lvalues{};
const int a = 1;
const int b = 2;
const int c = 3;
static_assert(are_values<values<1,2,3>>::value, "");
static_assert(!are_values<lvalues<a,b,c>>::value, "");
static_assert(!are_lvalues<values<1,2,3>>::value, "");
static_assert(are_lvalues<lvalues<a,b,c>>::value, "");