Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

function specialization based on if template parameter is shared_ptr

I'm trying to detect if a type is a shared_ptr<T> and if it is, dispatch to a specific function template or override.

Here's a simplified version of what I'm actually attempting:

#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;
}

It compiles just fine, but it seems the actual functions were never actually generated because the code doesn't link with the following errors:

/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

I would think that those would be covered by the two function templates. But they aren't.

Given that, it seems I am seriously misunderstanding something.

So maybe it would help if I explain what I'm /trying/ to do rather than what I'm actually doing.

I have some "magic" code using a bunch of new (to me) C++11 features to bind C++ code to lua (can be seen here: https://github.com/Tomasu/LuaGlue). someone has recently asked for support for binding to classes wrapped in shared_ptr's. which is not something that works at the moment, because it binds at compile time using templates and tuple unwrapping to generate code to call functions on either the C++ or lua side. In the "magic" unwrapping code, I have a bunch of overridden and "specialized" functions that handle various variable types. Some for basic types, one for static objects, and another for pointer to objects. A shared_ptr can't be handled in the same way as either a static or pointer object, so I need to add some extra handling just for them.

For example:

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>());
}

That's the actual code (notice the hairy template/override via function argument :-x).

I had thought it'd be as simple as adding another addValue function, along the lines of the code in my earlier example, via enable_if.

like image 353
Tomasu Avatar asked Nov 29 '13 15:11

Tomasu


1 Answers

Any reason not to simply use partial specialization?

#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;
}
like image 131
zennehoy Avatar answered Oct 02 '22 08:10

zennehoy