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

时间:2018-02-10 05:16:16

标签: c++ templates template-meta-programming sfinae

我需要使用静态成员变量模板foo定义一个类foo::static_variable_template<T>。该成员应仅在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的公共接口中。

这在C ++ 17中是否可行?

1 个答案:

答案 0 :(得分:1)

我不确定如果foo::static_variable_template丢失,或者您想要完全禁用它,那么您的意图是0T::constexpr_static_function()初始化。如果是前者,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禁用静态模板变量。引用伟大的黎曼的话说,“我暂时没有尝试过一些短暂的尝试,暂时搁置对此的搜索......”