关于c ++:如何检查静态成员变量模板?

How to check for static member variable template?

我需要用静态成员变量模板foo::static_variable_template定义一个类foo。只有当T满足某些要求时,该成员才存在。例如,当constexr静态函数T::constexpr_static_function()存在时。否则,foo::static_variable_template不应存在。此外,我希望能够在编译时通过sfinae测试foo::static_variable_template的存在性。

下面是我想要做的一个近似值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>

struct foo
{
  template<class T>
    static constexpr int static_variable_template =
      T::constexpr_static_function();

// XXX this works but requires a second defaulted template parameter
//  template<class T, int = T::constexpr_static_function()>
//    static constexpr int static_variable_template =
//      T::constexpr_static_function();
};

struct has_constexpr_static_function
{
  static constexpr int constexpr_static_function() { return 42; }
};

struct hasnt_constexpr_static_function
{
};

template<class T, class U,
  int = T::template static_variable_template<U>>
void test_for_static_variable_template(int)
{
  std::cout <<"yes it has
"
;
}

template<class T, class U>
void test_for_static_variable_template(...)
{
  std::cout <<"no it hasn't
"
;
}

int main()
{
  test_for_static_variable_template<foo, has_constexpr_static_function>(0);
  test_for_static_variable_template<foo, hasnt_constexpr_static_function>(0);
}

这种近似几乎可以工作,但前提是foo::static_variable_template有第二个默认模板参数。因为第二个参数是一个实现细节,所以我想将其隐藏在foo::static_variable_template的公共接口中。

在C++ 17中这是可能的吗?


我不确定您是否打算用0初始化foo::static_variable_template,如果缺少T::constexpr_static_function(),或者您想完全禁用它。对于前者,这可能会有用。例如,这个(笨拙)的解决方案是有效的(需要C++ 17用于EDCOX1,3);注意你的变量现在是一个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>

template <typename T>
class has_func
{
    typedef char does;
    typedef long doesnt;

    template <typename C> static does test( decltype(&C::constexpr_static_function) );
    template <typename C> static doesnt test(...);

public:
    static constexpr bool value()
    {
        return sizeof(test<T>(0)) == sizeof(char);
    }
};

struct foo
{
    template<class T>
    static constexpr int static_variable_template()
    {
        if constexpr (has_func<T>::value())
        {
            return T::constexpr_static_function();
        }
        return 0;
    }

    // XXX this works but requires a second defaulted template parameter
    //  template<class T, int = T::constexpr_static_function()>
    //    static constexpr int static_variable_template =
    //      T::constexpr_static_function();
};

struct has_constexpr_static_function
{
    static constexpr int constexpr_static_function() { return 42; }
};

struct hasnt_constexpr_static_function
{
};

template<class T, class U>
void test_for_static_variable_template(...)
{
    if constexpr (has_func<U>::value())
    {
        std::cout <<"yes it has
"
;
    }
    else
    {
        std::cout <<"no it hasn't
"
;
    }
}

int main()
{
    std::cout << foo::static_variable_template<has_constexpr_static_function>() <<"
"
;
    std::cout << foo::static_variable_template<hasnt_constexpr_static_function>() <<"
"
;

    /// Original test
    test_for_static_variable_template<foo, has_constexpr_static_function>(0);
    test_for_static_variable_template<foo, hasnt_constexpr_static_function>(0);
}

印刷品

1
2
3
4
42
0
yes it has
no it hasn't

clang 5.0.1测试。

如果要完全禁用foo::static_variable_template,可能需要使用std::enable_if

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>

template <typename T>
class has_func
{
    typedef char does;
    typedef long doesnt;

    template <typename C> static does test( decltype(&C::constexpr_static_function) );
    template <typename C> static doesnt test(...);

public:
    static constexpr bool value()
    {
        return sizeof(test<T>(0)) == sizeof(char);
    }
};

struct foo
{
    template<class T, typename std::enable_if<has_func<T>::value()>::type ...>
    static constexpr int static_variable_template()
    {
        if constexpr (has_func<T>::value())
        {
            return T::constexpr_static_function();
        }
        return 0;
    }

    // XXX this works but requires a second defaulted template parameter
    //  template<class T, int = T::constexpr_static_function()>
    //    static constexpr int static_variable_template =
    //      T::constexpr_static_function();
};

struct has_constexpr_static_function
{
    static constexpr int constexpr_static_function() { return 42; }
};

struct hasnt_constexpr_static_function
{
};

template<class T, class U>
void test_for_static_variable_template(...)
{
    if constexpr (has_func<U>::value())
    {
        std::cout <<"yes it has
"
;
    }
    else
    {
        std::cout <<"no it hasn't
"
;
    }
}

int main()
{

    std::cout << foo::static_variable_template<has_constexpr_static_function>() <<"
"
;
    // We can't print this because it doesn't exist.
    // std::cout << foo::static_variable_template<hasnt_constexpr_static_function>() <<"
";

    /// Original test
    test_for_static_variable_template<foo, has_constexpr_static_function>(0);
    test_for_static_variable_template<foo, hasnt_constexpr_static_function>(0);
}

在这一思路中,我不确定是否可以使用std::enable_if禁用静态模板变量。引用伟大的黎曼的话,"在短暂的徒劳尝试之后,我暂时放弃了寻找这个……"