如何检查静态成员变量模板?

How to check for static member variable template?

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

这是我想做的事情的近似值:

#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\n";
}

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

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.

的 public 接口中隐藏它

这在 C++17 中可行吗?

我不确定您的意图是在缺少 T::constexpr_static_function() 时用 0 初始化 foo::static_variable_template 还是您想完全禁用它。如果是前者,this 可能会有用。例如,这个(笨拙的)解决方案有效(if constexpr 需要 C++17;请注意,您的变量现在是一个函数):

#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\n";
    }
    else
    {
        std::cout << "no it hasn't\n";
    }
}

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

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

打印

42
0
yes it has
no it hasn't

使用 clang 5.0.1 测试。

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

#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\n";
    }
    else
    {
        std::cout << "no it hasn't\n";
    }
}

int main()
{

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

    /// 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 禁用静态模板变量。引用伟大的黎曼的话,"I have for the time being, after some fleeting vain attempts, provisionally put aside the search for this..."