Use*_*645 4 c++ friend template-meta-programming constexpr
这个问题是基于这篇文章。
目标:我想知道一个类是否有成员变量x。我想收到true无论此变量是否为private,public或protected。
方法:如果类有成员变量,您可以使用以下代码获取信息:
template <typename T, typename = int>
struct HasX : std::false_type { };
template <typename T>
struct HasX <T, decltype((void) T::x, 0)> : std::true_type { };
Run Code Online (Sandbox Code Playgroud)
使用它
if constexpr (HasX<my_class>::value) {
// do stuff with x
} else {
// ...
}
Run Code Online (Sandbox Code Playgroud)
上面的代码在这种情况下不起作用
struct my_class {
private:
int x;
};
Run Code Online (Sandbox Code Playgroud)
我怎样才能使这项工作?我想HasX<my_class>::value是true。
想法:
使用friend可以访问T::x. 这似乎不起作用。看看这个活生生的例子。
嗯......不确定这个解决方案的正确性和局限性......但是......
如果您定义了一个具有x可访问元素的辅助结构
struct check_x_helper
{ int x; };
Run Code Online (Sandbox Code Playgroud)
您可以编写一个模板结构,该结构继承自check_x_helper您想要查看的类是否包含x成员
template <typename T>
struct check_x : public T, check_x_helper
Run Code Online (Sandbox Code Playgroud)
在里面check_x你可以声明(仅声明:在 a 中使用decltype())如下
template <typename U = check_x, typename = decltype(U::x)>
static constexpr std::false_type check (int);
static constexpr std::true_type check (long);
Run Code Online (Sandbox Code Playgroud)
观察第一个,模板一个:当被检查的类(T)包含一个x成员时, thedecltype(U::x)是不明确的,因为它x是从Tand继承的check_x_helper,所以这个函数被 SFINAE 丢弃。
相反,当T不包含x成员时,没有歧义,decltype(U::x)是check_x_helper::x( int)的类型,第一个check()函数保持启用状态。
现在你需要一些东西
using type = decltype(check(0));
static constexpr auto value = type::value;
Run Code Online (Sandbox Code Playgroud)
调用check(0)(int参数表示对模板版本的偏好)并将检测到的保存value在static constexpr变量中。
下面是一个完整的编译示例
#include <iostream>
#include <utility>
class foo
{ int x; };
struct bar
{ };
struct check_x_helper
{ int x; };
template <typename T>
struct check_x : public T, check_x_helper
{
template <typename U = check_x, typename = decltype(U::x)>
static constexpr std::false_type check (int);
static constexpr std::true_type check (long);
using type = decltype(check(0));
static constexpr auto value = type::value;
};
int main()
{
std::cout << check_x<foo>::value << std::endl;
std::cout << check_x<bar>::value << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
此解决方案的缺点:decltype(U::x)在T声明x为方法或using类型时也会失败(歧义)。所以给出
class foo
{ int x () { return 0;} ; };
Run Code Online (Sandbox Code Playgroud)
或者
class foo
{ using x = int; };
Run Code Online (Sandbox Code Playgroud)
从check_x<foo>::value您那里获得1.