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.
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;
}
Your program declares template<class T> void getValue() but doesn't define it. template <typename, typename> void getValue() is a different function. The compiler is picking template<class T> void getValue() as a better match with your invocations, which of course fails at link time as there is no definition of that function.
I prefer the simplicity of tag dispatch when it's applicable (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>{});
}
Here is another solution which is basically a fix for the OP rather than alternatives (using a class and its constructor as in zennehoy's post or tag dispatch as in 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");
}
I must say that, as Casey has put it, I also "prefer the simplicity of tag dispatch". Hence, I would go for his solution.
I also found zennehoy's idea interesting but, unfortunately, it doesn't allow your function to return something. (I believe a workaround is possible but it adds complexity.) With the solution here you just need to provide the return type as the 2nd parameter of std::enable_if.
Related
I'm currently writing a template class for archiving (or serializing) and unarchiving data into/from a binary format. First off, I'm trying to close on what pattern I'll use. I am mostly inclined to using templates because unarchivers don't have an input type for method overloading. For instance, the following example is OK:
Archiver ar;
int i;
archive(ar, i);
But it's counterpart isn't:
Unarchiver unar;
int i;
i = unarchive(unar);
I would like to avoid using the function's name, such as unarchive_int because it would be troublesome when using templates. Say:
template <class T> class SomeClass
{
public:
void doSomething()
{
// Somewhere
T value = unarchive(unar);
}
};
This would make things messy, and as such I rather really use templates for this, whereas the previous expression would be T value = unarchive<T>(ar);. It also seems silly (arguably) to write a global function if either the first or only parameter are always the archiver and unarchiver objects; a template class seems to be in order:
template <class T> class Archiver
{
public:
void archive(T obj);
};
This works, but the archiving method always copies its input object. This is OK with POD data types, but not so much which classes. The solution seems obvious, and instead use a const reference as in void archive(const T & obj), but now it also seems silly to be passing integers, floats, and other PODs by reference. Although I would be happy with this solution, I tried to go a little further and have the object make the distinction instead. My first approach is std::enable_if, while assuming a copy by default (for all non-class members) and provide a class specialization where the archive method gets its input by reference instead. It doesn't work. Here's the code:
template <class T, class E = void>
class Archiver
{
public:
// By default, obj is passed by copy
void archive(T obj);
};
template <class T>
class Archiver<T, typename std::enable_if<std::is_class<T>::value && !std::is_pod<T>::value>::value>
{
public:
// I would expect this to be used instead if is_class<T> && !is_pod<T>
void archive(const T & obj);
};
The problem is that the second declaration is not visible at all to the compiler, and here's proof:
template <> void Archiver<std::uint8_t>::archive(uint8_t obj);
template <> void Archiver<std::string>::archive(const std::string & obj);
The former compiles fine, but the later gives:
out-of-line declaration of 'archive' does not match any declaration in
'Archiver<std::__1::basic_string<char>, void>'
On the other hand, if I get the std::string instead by copy if compiles just fine. I think I know why this happens, the compiler chooses the first template as it's generic enough for both declarations, but then how do I make it choose the more specialized version?
You want std::enable_if<...>::type, not std::enable_if<...>::value.
Here's a full demo:
#include <type_traits>
#include <cstdint>
#include <string>
template <class T, class E = void>
struct Archiver {
void archive(T obj);
};
template <class T>
struct Archiver<T, typename std::enable_if<std::is_class<T>::value && !std::is_pod<T>::value>::type>
{
void archive(const T & obj);
};
template <> void Archiver<std::uint8_t>::archive(std::uint8_t obj);
template <> void Archiver<std::string>::archive(const std::string & obj);
IIUC, the question boils down to how to define a generic template type that is optimized for calling functions.
For this, you can consider boost::call_traits, in particular, param_type:
template<typename T>
void foo(typename boost::call_traits<T>::param_type t);
How does one specialize a template function to generate an error at compile-time if a user attempts to call said function with a given template parameter?
I was able to get this behavior for a template class by using the following idiom...
template <typename T>
class MyClass< std::vector<T> >;
The basic signature of the function which I am trying to modify is...
template <typename T>
T bar(const int arg) const {
...
}
If I use the same paradigm that I used to disallow certain template classes...
template<>
std::string foo::bar(const int arg) const;
I can generate a linker error, which I suppose is more desirable than a runtime error, but still not really what I'm looking for.
Since I am not able to use C++11, I cannot use static_assert, as described here. Instead, I am trying to use BOOST_STATIC_ASSERT like so...
template<>
std::string foo::bar(const int arg) const {
BOOST_STATIC_ASSERT(false);
return "";
}
However, this generates the following compile-time error, even when I am not trying to call an instance of the function with the template parameter I am attempting to disallow...
error: invalid application of 'sizeof' to incomplete type 'boost::STATIC_ASSERTION_FAILURE<false>'
I found this post, but it doesn't really offer any insight that I feel applies to me. Can anyone help?
Use boost::is_same to generate a compile-time boolean value that can then be used with BOOST_STATIC_ASSERT to perform the check.
template <typename T>
T bar(const int)
{
BOOST_STATIC_ASSERT_MSG((!boost::is_same<T, std::string>::value),
"T cannot be std::string");
return T();
}
bar<int>(10);
bar<std::string>(10); // fails static assertion
Live demo
It seems C++ don't allow specialize template member function. So if you want to use same interface, you should use other technology. I'd like to use trait_type to implement this.
template <class T>
struct is_string : false_type {};
template <>
struct is_string<string> : true_type {};
template <typename T>
class MyClass {
private:
T bar(const int arg, false_type) const {
return T();
}
std::string bar(const int arg, true_type) const {
return "123";
}
public:
T bar(const int arg) const {
return bar(arg, is_string<T>());
}
};
If you can not use C++11, you must implement false_type and true_type yourself. Or you can use specialize template class.
Imagine a class (in VS2010, no variadic templates here sorry)
template <class Arg>
class FunctionWrapper
{
public:
void Invoke(Arg arg){_fn(arg)};
private:
std::function<void(Arg)> _fn;
}
I can then do e.g.
FunctionWrapper <int> foo; foo.Invoke(4);
And this compiles fine. But this does not:
FunctionWrapper <void> foo; foo.Invoke();
Now, I could get around this using template specialization. But I also wondered if there was a way I could get around this another way....
template <class Arg>
class FunctionWrapper
{
public:
void Invoke(void){_fn()}; // } overloaded
void Invoke(Arg arg){_fn(arg)}; // }
private:
std::function<void(Arg)> _fn;
}
i.e. Overload Invoke, and then reply on conditional compilation so that if I instantiate
FunctionWrapper<void>,
the version of Invoke with the argument never gets compiled. I'm sure I read how to do this in Modern C++ design, but I can't remember the details.....
If you were trying to implement a functor this way there would be a number of obvious flaws in the design; I assume, and you seem to make it clear on the comments, that the code is just, well, an example used to state your case.
Here are a couple of solutions to the problem:
template<class T>
struct Trait{
typedef T type;
typedef T mock_type;
};
template<>
struct Trait<void>{
typedef void type;
typedef int mock_type;
};
template <class Arg>
class FunctionWrapper
{
public:
void Invoke(void){_fn();}
void Invoke(typename Trait<Arg>::mock_type arg){_fn(arg);}
boost::function<void(typename Trait<Arg>::type)> _fn;
private:
};
template <class Arg>
class FunctionWrapper2
{
public:
FunctionWrapper2(const boost::function<void(Arg)> arg) : Invoke(arg){}
const boost::function<void(Arg)> Invoke;
};
int main(int argc, _TCHAR* argv[])
{
FunctionWrapper<int> cobi;
cobi._fn = &countOnBits<int>;
cobi.Invoke(5);
FunctionWrapper<void> cobv;
cobv._fn = &func;
cobv.Invoke();
FunctionWrapper2<int> cobi2(&countOnBits<int>);
cobi2.Invoke(5);
FunctionWrapper2<void> cobv2(&func);
cobv2.Invoke();
//[...]
}
Of course I'm not saying that what I wrote is good code, as for the question it is only intended to provide examples of working constructs.
The problem with your attempt is that while the function void Invoke(Arg arg){_fn(arg)}; is actually not being compiled when you instanciate FunctionWrapper (and don't make any attempt at invoking the Invoke function with a parameter), it gets syntactically checked; and of course Invoke(void arg) is not something your compiler is going to accept!
This is my first answer on stackoverflow, I hope I had everything right; if not, please give me some feedback and don't get too upset at me :)
I have a class named has_f and I want it to only accept template parameters that have a f member function. How would I do that? This is what I tried:
template <typename T, typename = void>
struct has_f : std::false_type {};
template <typename T>
struct has_f<
T,
typename = typename std::enable_if<
typename T::f
>::type
> : std::true_type {};
But I get some cryptic errors. Here is the class I want to use:
struct A
{
void f();
};
How do I do this correctly? Thanks.
From the title of your question I presume that you don't really need a type deriving from true_type or false_type - only to prevent compilation if method f is not present. If that is the case, and if you also require a specific signature (at least in terms of arguments) for that method, in C++11 you can do something like this:
template <typename T>
struct compile_if_has_f
{
static const size_t dummy = sizeof(
std::add_pointer< decltype(((T*)nullptr)->f()) >::type );
};
This is for the case when f() should not accept any arguments. std::add_pointer is only needed if f returns void, because sizeof(void) is illegal.
I +1ed rapptz yesterday for
"possible duplicate of
Check if a class has a member function of a given signature"
and haven't changed my mind.
I suppose it is arguable that this question unpacks to
"A) How to check if a class has a member function of a given signature and
B) How to insist that a class template argumement is a class
as per A)". To B) in this case I would answer with static_assert, since
the questioner apparently isn't interested in enable_if alternatives.
Here is a solution that adapts my answer to
"traits for testing whether func(args) is well-formed and has required return type"
This solution assumes that has_f<T>::value should be true if and only
if exactly the public member void T::f() exists, even if T overloads f or inherits f.
#include <type_traits>
template<typename T>
struct has_f
{
template<typename A>
static constexpr bool test(
decltype(std::declval<A>().f()) *prt) {
return std::is_same<void *,decltype(prt)>::value;
}
template <typename A>
static constexpr bool test(...) {
return false;
}
static const bool value = test<T>(static_cast<void *>(nullptr));
};
// Testing...
struct i_have_f
{
void f();
};
struct i_dont_have_f
{
void f(int);
};
struct i_also_dont_have_f
{
int f();
};
struct i_dont_quite_have_f
{
int f() const;
};
struct i_certainly_dont_have_f
{};
struct i_have_overloaded_f
{
void f();
void f(int);
};
struct i_have_inherited_f : i_have_f
{};
#include <iostream>
template<typename T>
struct must_have_f{
static_assert(has_f<T>::value,"T doesn't have f");
};
int main()
{
must_have_f<i_have_f> t0; (void)t0;
must_have_f<i_have_overloaded_f> t1; (void)t1;
must_have_f<i_have_inherited_f> t2; (void)t2;
must_have_f<i_dont_have_f> t3; (void)t3; // static_assert fails
must_have_f<i_also_dont_have_f> t4; (void)t4; // static_assert fails
must_have_f<i_dont_quite_have_f> t5; (void)t5; // static_assert fails
must_have_f<i_certainly_dont_have_f> t6; (void)t6; // static_assert fails
must_have_f<int> t7; (void)t7; // static_assert fails
return 0;
}
(Built with clang 3.2, gcc 4.7.2/4.8.1)
This toes a fine line between answering your question and providing a solution to your problem but not directly answering your question, but I think you may find this helpful.
For background, check out this question. The author mentions that he didn't like Boost's solution, and I didn't particularly like the one proposed there either. I was writing a quick & dirty serialization library (think python's marshal) where you would call serialize(object, ostream) on an object to serialize it. I realized I wanted this function call to one of four things:
If object is plain old data, just write out the size and raw data
If object is a class that I've created with its own member function (object::serialize), then call that member function
If there's a template specialization for that type, use it.
If none of the above is true, throw a compilation error; the serialize function is being used improperly.
When I code, I try to avoid stuff that is 'tricky' or hard to understand at a glance. I think this solution solves the same problem without using code that must be pondered for hours to understand:
#include <type_traits>
#include <iostream>
#include <vector>
#include <string>
// Template specialization for a POD object
template<typename T>
typename std::enable_if< std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
os.write((const char*) &out, sizeof(T));
return os.good();
}
// Non POD objects must have a member function 'serialize(std::ostream)'
template<typename T>
typename std::enable_if< ! std::is_pod<T>::value, bool>::type
serial(const T &out, std::ostream &os)
{
return out.serial(os);
}
// Additional specializations here for common container objects
template<typename T>
bool serial(const std::vector<T> &out, std::ostream &os)
{
const size_t vec_size = out.size();
if(!serial(vec_size, os))
return false;
for(size_t i =0; i < out.size(); ++i)
{
if(!serial(out[i], os))
return false;
}
return true;
}
class SomeClass
{
int something;
std::vector<double> some_numbers;
...
bool serial(std::ostream &os)
{
return serial(something, os) && serial(some_numbers, os);
}
};
If you can boil down your needs to a simple set of rules, and can live with a slightly less general solution, I think this method works well.
As I understand it, when passing an object to a function that's larger than a register, it's preferable to pass it as a (const) reference, e.g.:
void foo(const std::string& bar)
{
...
}
This avoids having to perform a potentially expensive copy of the argument.
However, when passing a type that fits into a register, passing it as a (const) reference is at best redundant, and at worst slower:
void foo(const int& bar)
{
...
}
My problem is, I'd like to know how to get the best of both worlds when I'm using a templated class that needs to pass around either type:
template <typename T>
class Foo
{
public:
// Good for complex types, bad for small types
void bar(const T& baz);
// Good for small types, but will needlessly copy complex types
void bar2(T baz);
};
Is there a template decision method that allows me to pick the correct type? Something that would let me do,
void bar(const_nocopy<T>::type baz);
that would pick the better method depending on the type?
Edit:
After a fair amount of timed tests, the difference between the two calling times is different, but very small. The solution is probably a dubious micro-optimization for my situation. Still, TMP is an interesting mental exercise.
Use Boost.CallTraits:
#include <boost/call_traits.hpp>
template <typename T>
void most_efficient( boost::call_traits<T>::param_type t ) {
// use 't'
}
If variable copy time is significant, the compiler will likely inline that instance of a template anyway, and the const reference thing will be just as efficient.
Technically you already gave yourself an answer.
Just specialize the no_copy<T> template for all the nocopy types.
template <class T> struct no_copy { typedef const T& type; };
template <> struct no_copy<int> { typedef int type; };
The only solution I can think of is using a macro to generate a specialized template version for smaller classes.
First: Use const & - if the implementation is to large to be inlined, the cosnt & vs. argument doesn't make much of a difference anymore.
Second: This is the best I could come up with. Doesn't work correctly, because the compiler cannot deduce the argument type
template <typename T, bool UseRef>
struct ArgTypeProvider {};
template <typename T>
struct ArgTypeProvider<T, true>
{
typedef T const & ArgType;
};
template <typename T>
struct ArgTypeProvider<T, false>
{
typedef T ArgType;
};
template <typename T>
struct ArgTypeProvider2 : public ArgTypeProvider<T, (sizeof(T)>sizeof(long)) >
{
};
// ----- example function
template <typename T>
void Foo(typename ArgTypeProvider2<T>::ArgType arg)
{
cout << arg;
}
// ----- use
std::string s="fdsfsfsd";
// doesn't work :-(
// Foo(7);
// Foo(s);
// works :-)
Foo<int>(7);
Foo<std::string>(s);