具有特定方法的类的模板特化

时间:2016-09-28 03:56:23

标签: c++ templates c++11 template-specialization

我有一个Lua State类的模板化方法,它测试给定索引处的对象是否属于给定类型:

template<typename T> bool is(int idx) {
    return luaL_testudata(L, idx, std::remove_pointer<T>::type::name) != NULL;
};

和一些专业:

template<> inline bool State::is<bool>(int i){ return lua_isboolean(this->L, i); }
template<> inline bool State::is<int>(int i){ return lua_isinteger(this->L, i); }
//etc...

现在我想为任何具有静态“lua_test”方法的类添加特化:

template<> inline bool State::is<T>(int i){ return T::lua_test(this->L, i); }

但我不知道正确的语法。我最接近的是:

template <class T>
inline auto State::is(int idx) ->
decltype(std::declval<T>.lua_test(this, idx), true)
{
    return T::lua_test(this, idx);
}

这无法编译,因为显然类型不匹配:

templates.hpp:87:13: error: prototype for ‘decltype ((declval<T>.lua_test(((Lua::State*)this), idx), true)) Lua::State::is(int)’ does not match any in class ‘Lua::State’
 inline auto State::is(int idx) ->
             ^~~~~
In file included from [...],
                 from debug.cpp:1:
get.hpp:6:27: error: candidate is: template<class T> bool Lua::State::is(int)
 template<typename T> bool is(int idx) {

这个想法应该是decltype语句评估为decltype(true)(由于逗号运算符),即bool,但gcc似乎并不相信这一点。 / p>

这看起来应该很简单,但我一直在试图实现它。

2 个答案:

答案 0 :(得分:1)

将始终使用显式模板参数调用类方法is(),例如:is<some_type>(value)。因此,在这种情况下,您可以将其作为static函数包含在类中,以简化template特化。

template<typename T, typename = void>
struct X {   // default
  static bool is (int idx) { return ...; } 
};

template<>
struct X<int, void> {   // `int` specialization
  static bool is (int idx) { return lua_isinteger(...); } 
};

template<>
struct X<bool, void> {   // `bool` specialization
  bool is (int idx) { return lua_isboolean(...); } 
};

<强>专业化

现在我们保留typename = void以便于SFINAE如下:

template<typename T> struct void_ { using type = void; };

template<typename T>  // specialization for those, who contain `lua_test`
struct X<T, typename void_<decltype(&T::lua_test)>::type> { 
  static bool is (int idx) { return T::lua_test(...); } 
};

<强>用法

X<some_class>::is(0);
X<int>::is(1);
X<bool>::is(2);
X<some_class_with_lua_test_function>::is(3);

它编译&amp;在我的环境中工作,因此,它也适合你!

修改:我发现您在此方法中使用了this。在这种情况下,您的方法可能如下所示:

template<typename T, typename = void>
struct X {   // default
  static bool is (Lua* const this_, int idx) { return ...; } 
};
// ... other specializations with similar syntax

答案 1 :(得分:1)

您可以在decltype

中重复返回
struct State
{
    // ....

    template <class T>
    auto is(int idx) -> decltype(T::lua_test(this, idx))
    {
        return T::lua_test(this, idx);
    }
};

对于你的情况,你必须做一些工作,不要在这两种方法之间进行模糊的调用。

struct low_priority {};
struct high_priority : low_priority {};

struct State
{
public:
    template<typename T>
    bool is(int idx) {
        return is_impl<T>(idx, high_priority{});
    }

private:
    template<typename T>
    bool is_impl(int idx, low_priority) {
        std::cout << "generic\n";
        return luaL_testudata(L, idx, std::remove_pointer<T>::type::name) != NULL;
    }

    template <class T>
    auto is_impl(int idx, high_priority) -> decltype(T::lua_test(this, idx))
    {
        std::cout << "LuaTest\n";
        return T::lua_test(this, idx);
    }

    LuaState L;
};

Demo