函数专门化基于if模板参数是shared_ptr

时间:2013-11-29 15:01:08

标签: c++ templates c++11

我正在尝试检测某个类型是否为shared_ptr<T>,如果是,则调度到特定的函数模板或覆盖。

这是我实际尝试的简化版本:

#include <type_traits>
#include <memory>
#include <cstdio>

template <class T> struct is_shared_ptr : std::false_type {};
template <class T> struct is_shared_ptr<std::shared_ptr<T> > : std::true_type {};

class Foo { };
typedef std::shared_ptr<Foo> SharedFoo;

template<class T> void getValue();

template<class T, typename std::enable_if<is_shared_ptr<T>::value>::type = 0>
void getValue()
{
    printf("shared!\n");
}

template<class T, typename std::enable_if<!is_shared_ptr<T>::value>::type = 0>
void getValue()
{
    printf("not shared!\n");
}

int main(int, char **)
{
    getValue<SharedFoo>();
    getValue<Foo>();
    return 0;
}

它编译得很好,但似乎实际的函数从未实际生成,因为代码没有链接以下错误:

/tmp/ccjAKSBE.o: In function `main':
shared_test.cpp:(.text+0x10): undefined reference to `void getValue<std::shared_ptr<Foo>>()'
shared_test.cpp:(.text+0x15): undefined reference to `void getValue<Foo>()'
collect2: error: ld returned 1 exit status

我认为这些将由两个功能模板涵盖。但他们不是。

鉴于此,我似乎误解了一些事情。

所以,如果我解释一下我正在做什么/尝试做什么而不是我实际做的事情,这可能会有所帮助。

我有一些“魔术”代码使用一堆新的(对我来说)C ++ 11特性来将C ++代码绑定到lua(可以在这里看到:https://github.com/Tomasu/LuaGlue)。有人最近要求支持绑定shared_ptr中包含的类。这不是目前可用的东西,因为它在编译时使用模板和元组解包绑定生成代码以在C ++或lua端调用函数。在“神奇”的展开代码中,我有一堆被覆盖的“专用”函数来处理各种变量类型。一些用于基本类型,一个用于静态对象,另一个用于指向对象。 shared_ptr无法以与静态或指针对象相同的方式处理,因此我需要为它们添加一些额外的处理。

例如:

template<typename T>
T getValue(LuaGlue &, lua_State *, unsigned int);

template<>
int getValue<int>(LuaGlue &, lua_State *state, unsigned int idx)
{
    return luaL_checkint(state, idx);
}

template<class T>
T getValue(LuaGlue &g, lua_State *state, unsigned int idx)
{
    return getValue_<T>(g, state, idx, std::is_pointer<T>());
}

这是实际的代码(通过函数参数注意毛茸茸的模板/覆盖:-x)。

我原以为它就像在前面的例子中通过addValue添加另一个enable_if函数一样简单。

3 个答案:

答案 0 :(得分:5)

任何不使用部分专业化的理由?

#include <type_traits>
#include <memory>
#include <cstdio>

class Foo { };
typedef std::shared_ptr<Foo> SharedFoo;

template <class T>
struct getValue {
    getValue() {
        printf("not shared!\n");
    }
};

template <class T>
struct getValue<std::shared_ptr<T> > {
    getValue() {
        printf("shared!\n");
    }
};

int main(int, char **)
{
    getValue<SharedFoo>();
    getValue<Foo>();
    return 0;
}

答案 1 :(得分:2)

您的程序声明template<class T> void getValue()但未定义它。 template <typename, typename> void getValue()是一个不同的功能。编译器选择template<class T> void getValue()作为与您的调用更好的匹配,当然在链接时失败,因为没有该函数的定义。

我更喜欢标签发送的简单性(适用于live at Coliru):

template<class T>
void getValue(std::true_type)
{
    printf("shared!\n");
}

template<class T>
void getValue(std::false_type)
{
    printf("not shared!\n");
}

template<class T>
void getValue() {
    return getValue<T>(is_shared_ptr<T>{});
}

答案 2 :(得分:0)

这是另一个解决方案,它基本上是对OP而不是替代方案的修复(使用类及其构造函数,如zennehoy的post或标签分派,如Casey's)。

// Do not provide this declaration:
// template<class T> void getValue();

template<class T>
typename std::enable_if<is_shared_ptr<T>::value>::type
getValue()
{
    printf("shared!\n");
}

template<class T>
typename std::enable_if<!is_shared_ptr<T>::value>::type
getValue()
{
    printf("not shared!\n");
}

我必须说,正如Casey所说,我也“更喜欢标签发送的简单性”。因此,我会寻求他的解决方案。

我也发现zennehoy的想法很有趣,但不幸的是,它不允许你的函数返回一些东西。 (我相信解决方法是可行的,但会增加复杂性。)在这里使用解决方案,您只需要提供返回类型作为std::enable_if的第二个参数。