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);
Related
I think the problem is fairly common, so there should be a known solution. I came up with one, but I'm not really satisfied, so I'm asking here, hoping someone can help.
Say I have a function, whose signature is
template<typename T>
void foo(const MyArray<const T>& x);
The const in the template parameter is to prevent me from changin the array content, since (for reasons beyond this question), the accessors ([] and ()) of MyArray<T> are always marked const, and return references to T (hence, the const ensure safety, since MyArray<T>::operator[] returns T&, while MyArray<const T>::operator[] returns const T&).
Great. However, templates with different template arguments are non related, so I can't bind a reference to MyClass<T> to a reference of MyClass<const T>, meaning I can't do this
MyArray<double> ar(/*blah*/);
foo(ar);
Notice that, without a reference, the code above would work provided that there is a copy constructor that lets me create MyArray<const T> from MyArray<T>. However, I don't want to remove the reference, since the array construction would happen a lot of times, and, despite relatively cheap, its cost would add up.
So the question: how can I call foo with an MyArray<T>?
My only solution so far is the following:
MyArray<T> ar(/*blah*/);
foo(reinterpret_cast<MyArray<const T>>(ar));
(actually in my code I hid the reinterpret cast in an inlined function with more verbose name, but the end game is the same). The class MyArray does not have a specialization for const T that makes it not reinterpretable, so the cast should be 'safe'. But this is not really a nice solution to read. An alternative, would be to duplicate foo's signature, to have a version taking MyArray<T>, which implementation does the cast and calls the const version. The problem with this is code duplication (and I have quite a few functions foo that need to be duplicated).
Perhaps some extra template magic on the signature of foo? The goal is to pass both MyArray<T> and MyArray<const T>, while still retaining const-correctness (i.e., make the compiler bark if I accidentally change the input in the function body).
Edit 1: The class MyArray (whose implementation is not under my control), has const accessors, since it stores pointers. So calling v[3] will modify the values in the array, but not the members stored in the class (namely a pointer and some smart-pointer-like metadata). In other words, the object is de facto not modified by accessors, though the array is. It's a semantic distinction. Not sure why they went this direction (I have an idea, but too long to explain).
Edit 2: I accepted one of the two answers (though they were somewhat similar). I am not sure (for reasons long to explain) that the wrapper class is doable in my case (maybe, I have to think about it). I am also puzzled by the fact that, while
template<typename T>
void foo(const MyArray<const T>& x);
MyArray<int> a;
foo(a);
does not compile, the following does
void foo(const MyArray<const int>& x);
MyArray<int> a;
foo(a);
Note: MyArray does offer a templated "copy constructor" with signature
template<typename S>
MyArray(const MyArray<S>&);
so it can create MyArray<const T> from MyArray<T>. I am puzzled why it works when T is explicit, while it doesn't if T is a template parameter.
I would stay with
template<typename T>
void foo(const MyArray<T>&);
and make sure to instantiate it with const T (in unitTest for example).
Else you can create a view as std::span.
Something like (Depending of other methods provided by MyArray, you probably can do a better const view. I currently only used operator[]):
template <typename T>
struct MyArrayConstView
{
MyArrayConstView(MyArray<T>& array) : mArray(std::ref(array)) {}
MyArrayConstView(MyArray<const T>& array) : mArray(std::ref(array)) {}
const T& operator[](std::size_t i) {
return std::visit([i](const auto& a) -> const T& { return a[i]; }), mArray);
}
private:
std::variant<std::reference_wrapper<MyArray<T>>,
std::reference_wrapper<MyArray<const T>>> mArray;
};
and then
template <typename T>
void foo(const MyArrayConstView<T>&);
but you need to call it explicitly, (as deduction won't happen as MyArray<T> is not a MyArrayConstView)
MyArray<double> ar(/*blah*/);
foo(MyArrayConstView{ar});
foo<double>(ar);
Since you are not allowed to change MyArray, one option is to use an adapter class.
template <typename T>
class ConstMyArrayView {
public:
// Not an explicit constructor!
ConstMyArrayView(const MyArray<T>& a) : a_(a) {}
const T& operator[](size_t i) const { return a_[i]; }
private:
const MyArray<T>& a_;
};
template<typename T>
void foo(const ConstMyArrayView<T>& x);
MyArray<T> x;
foo(x);
But in the end, if you can change MyArray to match the const-correctness you want, or switch to a class that does, that'll be the better option.
Here's an ugly but effective way to have a function use one type, but also get the compiler to check that the same code would compile if it used a different type instead:
template <typename From, typename To>
struct xfer_refs_cv
{
using type = To;
};
template <typename From, typename To>
struct xfer_refs_cv<const From, To>
{
using type = const typename xfer_refs_cv<From, To>::type;
};
template <typename From, typename To>
struct xfer_refs_cv<volatile From, To>
{
using type = volatile typename xfer_refs_cv<From, To>::type;
};
template <typename From, typename To>
struct xfer_refs_cv<From&, To>
{
using type = typename xfer_refs_cv<From, To>::type&;
};
template <typename From, typename To>
struct xfer_refs_cv<From&&, To>
{
using type = typename xfer_refs_cv<From, To>::type&&;
};
template <typename CheckType, typename Func, typename CallType>
constexpr decltype(auto) check_and_call(Func&& f, CallType&& call_arg)
noexcept(noexcept(std::forward<Func>(f)(std::forward<CallType>(call_arg))))
{
(void) decltype(std::declval<Func&&>()
(std::declval<typename xfer_refs_cv<CallType&&, CheckType>::type>()), 0){};
return std::forward<Func>(f)(std::forward<CallType>(call_arg));
}
template<typename T>
void foo(const MyArray<T>& x)
{
check_and_call<MyArray<const T>>(
[](auto&& x) {
// Function implementation here.
}, x);
}
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);
When I have following pseudo-class:
template <class T> class tmplClass
{
void doSomething(T input);
};
Is there a way to change void doSomething(T input) to void doSomething(const T& input) when sizeof(T) is larger the the system architecture.
Means, when you have tmplClass<char> c; for example, use void doSomething(T input) and when you have tmplClass<[another big class with lots of variables]> use void doSomething(const T& input)
Do I get any optimization out of this?
Is there anything I have to do, or can gcc do this automatically
If I have to do something, what?
Sure:
template<typename T, bool=true>
struct eff_arg {
typedef T type;
};
template<typename T>
struct eff_arg<T, (sizeof(T)>sizeof(int))> {
typedef T const& type;
};
// C++11 addition
template<typename T>
using EffArg = typename eff_arg<T>::type;
use:
template <class T> class tmplClass
{
// C++11
void doSomething(EffArg<T> input);
// C++03
void doSomething(typename eff_arg<T>::type input);
};
and replace sizeof(int) with whatever type you want to use as the "point where you want to pass as a reference instead of by value".
Note that the size of a parameter is a mediocre way to make this decision: An extremely small class (even smaller than a pointer!) could have deep copy semantics where a large structure is duplicated when it is duplicated. And often the cut-off shouldn't be size of int or a pointer but bigger than that, because indirection has a cost.
An idea might be to copy only objects that don't manage resources and are sufficiently small. std::is_trivially_copyable<T>::value && (sizeof(T) <= 2*sizeof(void*)) might be the kind of check you should make before passing a T rather than a T const& when you have no need for a copy of the data.
This leads to the following:
template<typename T, bool=true>
struct eff_arg {
typedef T const& type;
};
template<typename T>
struct eff_arg<T,
std::is_trivially_copyable<T>::value
&& (sizeof(T)<=2*sizeof(void*))
> {
typedef T type;
};
template<typename T>
using EffArg = typename eff_arg<T>::type;
Yes, easy:
#include <type_traits>
template <typename T> struct Foo
{
void do_something(typename std::conditional<(sizeof(T) > sizeof(void *)),
T const &, T>::type x)
{
// ... use "x"
}
// ...
};
You might want to assign the resulting type to some type alias for easy reuse.
As #Yakk suggests, it might be good to also add std::is_trivially_copyable<T>::value to the condition to avoid accidentally copying something that's expensive to copy or that might throw.
I have a bunch of overloaded functions that operate on certain data types such as int, double and strings. Most of these functions perform the same action, where only a specific set of data types are allowed. That means I cannot create a simple generic template function as I lose type safety (and potentially incurring a run-time problem for validation within the function).
Is it possible to create a "semi-generic compile time type safe function"? If so, how? If not, is this something that will come up in C++0x?
An (non-valid) idea;
template <typename T, restrict: int, std::string >
void foo(T bar);
...
foo((int)0); // OK
foo((std::string)"foobar"); // OK
foo((double)0.0); // Compile Error
Note: I realize I could create a class that has overloaded constructors and assignment operators and pass a variable of that class instead to the function.
Use sfinae
template<typename> struct restrict { };
template<> struct restrict<string> { typedef void type; };
template<> struct restrict<int> { typedef void type; };
template <typename T>
typename restrict<T>::type foo(T bar);
That foo will only be able to accept string or int for T. No hard compile time error occurs if you call foo(0.f), but rather if there is another function that accepts the argument, that one is taken instead.
You may create a "private" templatized function that is never exposed to the outside, and call it from your "safe" overloads.
By the way, usually there's the problem with exposing directly the templatized version: if the passed type isn't ok for it, a compilation error will be issued (unless you know your algorithm may expose subtle bugs with some data types).
You could probably work with templates specializations for the "restricted" types you want to allow. For all other types, you don't provide a template specialization so the generic "basic" template would be used. There you could use something like BOOST_STATIC_ASSERT to throw a compile error.
Here some pseudo-code to clarify my idea:
template <typename T>
void foo(T bar) {BOOST_STATIC_ASSERT(FALSE);}
template<> // specialized for double
void foo(double bar) {do_something_useful(bar);};
Perhaps a bit ugly solution, but functors could be an option:
class foo {
void operator()(double); // disable double type
public:
template<typename T>
void operator ()(T bar) {
// do something
}
};
void test() {
foo()(3); // compiles
foo()(2.3); // error
}
Edit: I inversed my solution
class foo {
template<typename T>
void operator ()(T bar, void* dummy) {
// do something
}
public:
// `int` is allowed
void operator ()(int i) {
operator ()(i, 0);
}
};
foo()(2.3); // unfortunately, compiles
foo()(3); // compiles
foo()("hi"); // error
To list an arbitrary selection of types I suppose you could use a typelist. E.g see the last part of my earlier answer.
The usage might be something like:
//TODO: enhance typelist declarations to hide the recursiveness
typedef t_list<std::string, t_list<int> > good_for_foo;
template <class T>
typename boost::enable_if<in_type_list<T, good_for_foo> >::type foo(T t);
I want to do something like
template <typename T>
void foo(const T& t) {
IF bar(t) would compile
bar(t);
ELSE
baz(t);
}
I thought that something using enable_if would do the job here, splitting up foo into two pieces, but I can't seem to work out the details. What's the simplest way of achieving this?
There are two lookups that are done for the name bar. One is the unqualified lookup at the definition context of foo. The other is argument dependent lookup at each instantiation context (but the result of the lookup at each instantiation context is not allowed to change behavior between two different instantiation contexts).
To get the desired behavior, you could go and define a fallback function in a fallback namespace that returns some unique type
namespace fallback {
// sizeof > 1
struct flag { char c[2]; };
flag bar(...);
}
The bar function will be called if nothing else matches because the ellipsis has worst conversion cost. Now, include that candidates into your function by a using directive of fallback, so that fallback::bar is included as candidate into the call to bar.
Now, to see whether a call to bar resolves to your function, you will call it, and check whether the return type is flag. The return type of an otherwise chosen function could be void, so you have to do some comma operator tricks to get around that.
namespace fallback {
int operator,(flag, flag);
// map everything else to void
template<typename T>
void operator,(flag, T const&);
// sizeof 1
char operator,(int, flag);
}
If our function was selected then the comma operator invocation will return a reference to int. If not or if the selected function returned void, then the invocation returns void in turn. Then the next invocation with flag as second argument will return a type that has sizeof 1 if our fallback was selected, and a sizeof greater 1 (the built-in comma operator will be used because void is in the mix) if something else was selected.
We compare the sizeof and delegate to a struct.
template<bool>
struct foo_impl;
/* bar available */
template<>
struct foo_impl<true> {
template<typename T>
static void foo(T const &t) {
bar(t);
}
};
/* bar not available */
template<>
struct foo_impl<false> {
template<typename T>
static void foo(T const&) {
std::cout << "not available, calling baz...";
}
};
template <typename T>
void foo(const T& t) {
using namespace fallback;
foo_impl<sizeof (fallback::flag(), bar(t), fallback::flag()) != 1>
::foo(t);
}
This solution is ambiguous if the existing function has an ellipsis too. But that seems to be rather unlikely. Test using the fallback:
struct C { };
int main() {
// => "not available, calling baz..."
foo(C());
}
And if a candidate is found using argument dependent lookup
struct C { };
void bar(C) {
std::cout << "called!";
}
int main() {
// => "called!"
foo(C());
}
To test unqualified lookup at definition context, let's define the following function above foo_impl and foo (put the foo_impl template above foo, so they have both the same definition context)
void bar(double d) {
std::cout << "bar(double) called!";
}
// ... foo template ...
int main() {
// => "bar(double) called!"
foo(12);
}
litb has given you a very good answer. However, I wonder whether, given more context, we couldn't come up with something that's less generic, but also less, um, elaborate?
For example, what types can be T? Anything? A few types? A very restricted set which you have control over? Some classes you design in conjunction with the function foo? Given the latter, you could simple put something like
typedef boolean<true> has_bar_func;
into the types and then switch to different foo overloads based on that:
template <typename T>
void foo_impl(const T& t, boolean<true> /*has_bar_func*/);
template <typename T>
void foo_impl(const T& t, boolean<false> /*has_bar_func*/);
template <typename T>
void foo(const T& t) {
foo_impl( t, typename T::has_bar_func() );
}
Also, can the bar/baz function have just about any signature, is there a somewhat restricted set, or is there just one valid signature? If the latter, litb's (excellent) fallback idea, in conjunction with a meta-function employing sizeof might be a bit simpler. But this I haven't explored, so it's just a thought.
I think litb's solution works, but is overly complex. The reason is that he's introducing a function fallback::bar(...) which acts as a "function of last resort", and then goes to great lengths NOT to call it. Why? It seems we have a perfect behavior for it:
namespace fallback {
template<typename T>
inline void bar(T const& t, ...)
{
baz(t);
}
}
template<typename T>
void foo(T const& t)
{
using namespace fallback;
bar(t);
}
But as I indicated in a comment to litb's original post, there are many reasons why bar(t) could fail to compile, and I'm not certain this solution handles the same cases. It certainly will fail on a private bar::bar(T t)
If you're willing to limit yourself to Visual C++, you can use the __if_exists and __if_not_exists statements.
Handy in a pinch, but platform specific.
EDIT: I spoke too soon! litb's answer shows how this can actually be done (at the possible cost of your sanity... :-P)
Unfortunately I think the general case of checking "would this compile" is out of reach of function template argument deduction + SFINAE, which is the usual trick for this stuff. I think the best you can do is to create a "backup" function template:
template <typename T>
void bar(T t) { // "Backup" bar() template
baz(t);
}
And then change foo() to simply:
template <typename T>
void foo(const T& t) {
bar(t);
}
This will work for most cases. Because the bar() template's parameter type is T, it will be deemed "less specialised" when compared with any other function or function template named bar() and will therefore cede priority to that pre-existing function or function template during overload resolution. Except that:
If the pre-existing bar() is itself a function template taking a template parameter of type T, an ambiguity will arise because neither template is more specialised than the other, and the compiler will complain.
Implicit conversions also won't work, and will lead to hard-to-diagnose problems: Suppose there is a pre-existing bar(long) but foo(123) is called. In this case, the compiler will quietly choose to instantiate the "backup" bar() template with T = int instead of performing the int->long promotion, even though the latter would have compiled and worked fine!
In short: there's no easy, complete solution, and I'm pretty sure there's not even a tricky-as-hell, complete solution. :(
//default
//////////////////////////////////////////
template <class T>
void foo(const T& t){
baz(t);
}
//specializations
//////////////////////////////////////////
template <>
void foo(const specialization_1& t){
bar(t);
}
....
template <>
void foo(const specialization_n& t){
bar(t);
}
Are you not able to use full specialisation here (or overloading) on foo. By say having the function template call bar but for certain types fully specialise it to call baz?