I've looked over a few similar questions, but I'm still confused. I'm trying to figure out how to explicitly (not by compiler optimization etc) and C++03-compatible avoid copying of an object when passing it to a specialized template function. Here is my test code:
#include <iostream>
using namespace std;
struct C
{
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C)" << endl; }
~C() { cout << "~C()" << endl; }
};
template<class T> void f(T) { cout << "f<T>" << endl; }
// This shows two possible ways, I don't need two overloads
// If I do it like (2) the function is not called, only if I do it like (1)
template<> void f(C c) { cout << "f<C>" << endl; } // (1)
template<> void f(const C& c) { cout << "f<C&>" << endl; } // (2)
int main()
{
C c;
f(c);
return 0;
}
(1) accepts the object of type C, and makes a copy. Here is the output:
C()
C(C)
f<C>
~C()
~C()
So I've tried to specialize with a const C& parameter (2) to avoid this, but this simply doesn't work (apparently the reason is explained in this question).
Well, I could "pass by pointer", but that's kind of ugly. So is there some trick that would allow to do that somehow nicely?
EDIT: Oh, probably I wasn't clear. I already have a templated function
template<class T> void f(T) {...}
But now I want to specialize this function to accept a const& to another object:
template<> void f(const SpecificObject&) {...}
But it only gets called if I define it as
template<> void f(SpecificObject) {...}
Basically what I want to do with this specialization is to adapt the SpecificObject to the template interface like
template<> void f(SpecificObject obj){ f(obj.Adapted()); } // call the templated version
EDIT2: Ok, I can force the const C& specialization to be called this way:
f<const C&>(c);
but is there a way to make it work like this as just f(c)?
EDIT3: If someone would eventually have similar questions, I finally found this link in another question, and it is helpful: http://www.gotw.ca/publications/mill17.htm
You're conflating three issues: templates, overloading and argument passing.
Just remove the specializations and pass the argument as T const&.
Cheers & hth.,
Why don't you overload:
void f(const C& c) { cout << "f(const C&)" << endl; }
This would work:
int main()
{
C c;
f<const C&>(c);
return 0;
}
Your alternative:
template<typename T> void f(const boost::reference_wrapper<T const>& c)
{ cout << "f<boost_const_ref&>" << endl; }
int main()
{
C c;
f(boost::cref(c));
return 0;
}
In reality you would use boost::reference_wrapper to pass the reference through to where you want to use it. You can use get() to do that, although boost::reference_wrapper has an implicit conversion back to the reference, so you could probably get by without the partial-specialisation of the template and just passing boost::cref(c) to the regular one.
So if you don't always want to accept a const reference (which is reasonable for base types [int, long, float etc.]), you can use a little boost magic.
#include <iostream>
#include <boost/call_traits.hpp>
using namespace std;
struct C
{
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C)" << endl; }
//C& operator=(C const&) { cout << "C=C" << endl; return *this; }
~C() { cout << "~C()" << endl; }
};
template<class T> void foo(typename boost::call_traits<T>::param_type inst) { cout << "f<T>" << endl; }
// specialization for calling class C
template<> void foo<C>(boost::call_traits<C>::param_type inst) { cout << "f<C>" << endl; }
int main()
{
int i = 0;
foo<int>(i);
C c;
foo<C>(c);
return 0;
}
Your problem is that the actual parameter c isn't const, so the main template is a better match because it doesn't need to add 'const' to the type. If you try functions that pass by value and by non-const reference, the compiler will tell you that it cannot resolve that difference.
#include <iostream>
using namespace std;
struct C
{
C() { cout << "C()" << endl; }
C(const C&) { cout << "C(C)" << endl; }
~C() { cout << "~C()" << endl; }
};
template<class T> void f(const T&) { cout << "f<T>" << endl; }
int main()
{
C c;
f(c);
return 0;
}
This does do what you would like, but you must then use a const ref for all values passed into the function. I do not know if this was what you were looking for.
Related
I want to execute an overloaded function over a variant. The following code block works and compiles, but the visit invocation seems overly complex. Why can I not simply write:
std::visit(&f, something);
Working version and context:
#include <variant>
#include <string>
#include <iostream>
#include <functional>
struct A {
std::string name = "spencer";
};
struct B {
std::string type = "person";
};
struct C {
double age = 5;
};
void f(A a) {
std::cout << a.name << std::endl;
}
void f(B b) {
std::cout << b.type << std::endl;
}
void f(C c) {
std::cout << c.age << std::endl;
}
int main() {
std::variant<A, B, C> something{B{}};
std::visit([](auto&& x) {f(x);}, something);
}
Is there a simpler way?
std::visit(&f, something);
This is not valid, because f is not a single function. &f says "give me a pointer to f". But f isn't one thing; it's three functions which happen to share a name, with three separate pointers.
std::visit([](auto&& x) {f(x);}, something);
This creates a closure based on a template which generates code to do dispatch at compile-time. Effectively, it works as though we did
void f(A a) {
std::cout << a.name << std::endl;
}
void f(B b) {
std::cout << b.type << std::endl;
}
void f(C c) {
std::cout << c.age << std::endl;
}
struct F {
template<typename T>
void operator()(T x) {
f(x);
}
};
int main() {
std::variant<A, B, C> something{B{}};
std::visit(F(), something);
}
Which would force the C++ compiler, during template expansion, to produce something like
void f(A a) {
std::cout << a.name << std::endl;
}
void f(B b) {
std::cout << b.type << std::endl;
}
void f(C c) {
std::cout << c.age << std::endl;
}
struct F {
void operator()(A x) {
f(x);
}
void operator()(B x) {
f(x);
}
void operator()(C x) {
f(x);
}
};
int main() {
std::variant<A, B, C> something{B{}};
std::visit(F(), something);
}
If you want to eliminate the lambda wrapper, you need a single callable object that can be passed as an argument, and a function pointer will not suffice, as a function pointer can't do overload resolution. We can always make a functor object explicitly.
struct F {
void operator()(A a) {
std::cout << a.name << std::endl;
}
void operator()(B b) {
std::cout << b.type << std::endl;
}
void operator()(C c) {
std::cout << c.age << std::endl;
}
};
int main() {
std::variant<A, B, C> something{B{}};
std::visit(F(), something);
}
It's up to you whether or not you consider this cleaner than the previous approach. On the one hand, it's more like the traditional OOP visitor pattern, in that we have an object doing the visiting. On the other hand, it would be nice if we could pass the name of a function and have C++ understand what we mean, but that would either require special C++ syntax for std::visit or runtime-dispatch in the form of multimethods. Either way, it's unlikely to happen soon, or at all.
A variation of #Silvio's answer is to create a template overload type that inherits from your functions:
#include <variant>
#include <iostream>
struct A {
std::string name = "spencer";
};
struct B {
std::string type = "person";
};
struct C {
double age = 5;
};
template<typename...Func>
struct overload : Func... {
using Func::operator()...;
};
template<typename...Func> overload(Func...) -> overload<Func...>;
int main()
{
overload ovld {
[](A a) { std::cout << a.name << std::endl; },
[](B b) { std::cout << b.type << std::endl; },
[](C c) { std::cout << c.age << std::endl; }
};
std::variant<A, B, C> something{B{}};
std::visit(ovld, something);
}
Until C++17, the deduction guide is necessary for aggregate CTAD (Class Template Argument Deduction)
Is there a simpler way?
Well, there might be a syntactically more streamlined way:
You can use overloaded{} from the cppreference example right inside the std::visit:
std::visit(overloaded{
[](A a) { std::cout << a.name << std::endl; },
[](B b) { std::cout << b.type << std::endl; },
[](C c) { std::cout << c.age << std::endl; }
}, something);
here, the overloaded implementation is pretty simple and the only thing of interest may be the deduction guide in case you're not familiar with C++17 deduction guides yet
Or better yet, you can do a little twist with the same overloaded struct and make this possible:
something| match {
[](A a) { std::cout << a.name << std::endl; },
[](B b) { std::cout << b.type << std::endl; },
[](C c) { std::cout << c.age << std::endl; }
};
I personally like the latter version for it's more streamlined and it resembles the match clause from some other languages.
The implementation is actually pretty straightforward, the only 2 changes are:
you rename overloaded to whatever you like, here it's match
you overload operator| for it to work
template <typename... Ts, typename... Fs>
constexpr decltype(auto) operator| (std::variant<Ts...> const& v, match<Fs...> const& match) {
return std::visit(match, v);
}
I have this and a little more syntactic sugar (such as |is and |as "operator-lookalikes" for variant and any) in this repo :)
This code:
#include <iostream>
class A {};
class B : public A {};
class C {
public:
template <typename T>
void x(const T& t) {
std::cout << "template" << std::endl;
}
void x(const A*& a) {
std::cout << "a" << std::endl;
}
void x(const int& a) {
std::cout << "int" << std::endl;
}
template <typename T>
void y(T t) {
std::cout << "template" << std::endl;
}
void y(A* a) {
std::cout << "a" << std::endl;
}
void y(int a) {
std::cout << "int" << std::endl;
}
template <typename T>
void z(const T& t) {
std::cout << "template" << std::endl;
}
};
// Does not compile
// template <>
// void C::z(const A*& a) {
// std::cout << "a" << std::endl;
// }
template <>
void C::z(const int& a) {
std::cout << "int" << std::endl;
}
int main(int argc, char** argv) {
C c;
c.x(new A());
c.x(new B());
c.x(1);
c.y(new A());
c.y(new B());
c.y(1);
c.z(new A());
c.z(new B());
c.z(1);
}
Prints:
template
template
int
a
template
int
template
template
int
I have the following questions about that:
Why does void C::z(const int& a) compile but void C::z(const A*& a) does not?
What is a reasonable solution to problem? I need to have a templated function for generically handling a wide variety of arguments, but a large set of classes with a common base needs to be handled specifically. I need some approach that will print a a int.
Edit: Thanks to the suggestion of #AndyG I was able to resolve this with some type_traits and the code below:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <iostream>
class A {};
class B : public A {};
class C {
public:
template <typename T>
typename boost::disable_if<boost::is_base_of<A, typename boost::remove_pointer<T>::type>, void>::type x(const T& t) {
std::cout << "template" << std::endl;
}
void x(A*const& a) {
std::cout << "a" << std::endl;
}
void x(const int& a) {
std::cout << "int" << std::endl;
}
};
int main(int argc, char** argv) {
C c;
c.x(new A());
c.x(new B());
c.x(1);
}
The answer is because a const on a pointer type is a little weird.
What you want is this:
template <>
void C::z( A*const& a) {
std::cout << "a" << std::endl;
}
const needs to be read right to left. Since z accepts a T&, when you want to specialize for A* you need to place the const after A* instead of in front.
Demo
Consider the following code:
#include <cstdlib>
#include <iostream>
using std::cout;
using std::endl;
class A {
public:
virtual ~A() {
}
};
class B : public A {
};
void foo(A& a) {
cout << "A&" << endl;
}
void foo(const A& a) {
cout << "const A&" << endl;
}
void foo(A* a) {
cout << "A*" << endl;
}
void foo(const A* a) {
cout << "const A*" << endl;
}
template <class T>
void foo(T& a) {
cout << "T&" << endl;
}
template <class T>
void foo(const T& a) {
cout << "const T&" << endl;
}
template <class T>
void foo(T* a) {
cout << "T*" << endl;
}
template <class T>
void foo(const T* a) {
cout << "const T*" << endl;
}
int main(int argc, char** argv) {
B a;
foo(a);
B& b = a;
foo(b);
B* c = &a;
foo(c);
const B& d = a;
foo(d);
const B* e = &a;
foo(e);
return EXIT_SUCCESS;
}
Produces the following output:
T&
T&
T*
const T&
const T*
This output surprised me because I thought the function that was the closest match would be the one invoked. So I was expecting the output:
A&
A&
A*
const A&
const A*
Can someone explain why the template functions overloads are chosen over the base class overloads when I pass in a subclass (B) of the base class (A)?
This is the expected behavior. When you call foo(a); a is a B. So we would need a implicit conversion from a B to a A in order to call void foo(A& a). However since you also have
template <class T>
void foo(T& a) {
cout << "T&" << endl;
}
The template gets stamped out and you get void foo(B& a). This is a direct match and requires no conversion. This is the best function so that is why it is picked. This is the same for all of the other functions as well as T gets deduced to B which gives a better match then all of the A functions.
If you want to stop this you could use std::enable_if and check if the type is a derived class with std::is_base_of
I'm trying to write a simple function template in C++ in which I am printing out the value of a variable of unknown type. The problem is I can't figure out how to do this since the variable could either be a pointer or a primitive type. With the primitive type, I can simply print the value out; but pointers require de-referencing.
The following code gives me an error:
#include <iostream>
#include <type_traits>
using namespace std;
template<typename T>
void foo(T someVar) {
if(std::is_fundamental<T>::value) {
cout << "It's primitive! \n" << someVar << endl;
} else {
cout << "It's a pointer! \n" << *someVar << endl;
}
}
int main(int argc, char **argv) {
int x = 5;
foo(x);
int *y = new int();
*y = 5;
foo(y);
delete y;
return 0;
}
The error I get when I compile is:
test.cc: In function 'void foo(T) [with T = int]':
test.cc:19:8: instantiated from here
test.cc:13:5: error: invalid type argument of unary '*' (have 'int')
It's complaining that I'm trying to de-reference a primitive type from my first call to foo(), but that's exactly why I'm using the if-statement: to check if it's primitive or not. How would I go about implementing what I'm trying to do?
What you need to do, is write 2 versions of your templated function.
template<typename T>
void foo(T someVar) {
cout << "Assume it's primitive! \n" << someVar << endl;
}
template<typename T>
void foo(T* pVar) {
cout << "This is a pointer! \n" << *pVar << endl;
}
The compiler will choose the pointer version if it works, because it's more specific. If the type is not a (raw) pointer, it will default to the first version.
If you need smart pointers to be dereferenced, you can further overload your function definition.
Eg.
template<typename T>
void foo(std::shared_ptr<T> pVar) {
cout << "This is a shared pointer! \n" << *pVar << endl;
}
You need an additional layer of indirection.
#include <iostream>
template < typename T >
struct print_helper
{
static void
print(std::ostream& os, const T& value)
{
os << "The value is " << value << "\n";
}
};
template < typename T >
struct print_helper< T * >
{
static void
print(std::ostream& os, const T *const pointer)
{
os << "The pointer points to " << *pointer << "\n";
}
};
template < typename T >
void
foo(T whatever)
{
print_helper<T>::print(std::cout, whatever);
}
int
main()
{
const auto a = 42;
foo(a);
foo(&a);
}
Output:
The value is 42
The pointer points to 42
A solution I'm partial to for just printing nicely is to write a function to do the dereferencing.
template<typename T> T &deref(T &elem) { return elem; }
template<typename T> T &deref(T *elem) { return *elem; }
Then you can simply use deref(value) anywhere you don't know whether or not value will be a pointer, as long as you don't care which it is.
template<typename T>
void print(T t) {
std::cout << deref(t) << '\n';
}
Write the function twice:
struct Foo
{
template<typename T>
static void foo(T val) {
cout << "var: " << val << endl;
}
template<typename T>
static void foo(T* val) {
cout << "ptr: " << *val << endl;
}
};
To call:
int x;
int *y;
Foo::foo(x);
Foo::foo(y);
class Foo
{
friend class SquirrelVM;
public:
Foo() { cout << "Ctor" << endl; }
virtual ~Foo() { cout << "Dtor" << endl; }
Foo(const Foo & o) { cout << "const Ctor" << endl; }
template <typename _ty>
Foo(const _ty & val) { cout << "T const Ref" << endl; }
template <typename _ty>
Foo(_ty & val) { cout << "T Ref" << endl; }
template <typename _ty>
Foo(_ty * val) { cout << "T Ptr" << endl; }
};
Foo CreateFoo()
{
Foo ret;
return ret;
}
int main( int argc, char* argv[] )
{
Foo f = CreateFoo();
return 0;
}
Outputs are different between vs2005 and vs 2010.
Expected outputs are like this..
Ctor
const Ctor
Dtor
Dtor
Above outputs are derived if I build in vs2005.
But, vs2010's output is not same with vs2005's
Ctor
T Ref
Dtor
Dtor
Why template function's priority is higher than normal function in vs2010?
[edit]
If const is ommitted on copy constructor, than expected output(which is same with vs2005) comes out. Is there any side effect if form of copy constructor is not same with recomended form? Recomended form.. I mean... Foo(const Foo&); not Foo(Foo&);
Foo(_ty & val) with _ty being Foo is a better match because it will have parameter type Foo& matching a non-const Foo lvalue, while the other has a const that will make it a bit worse match.
There was some confusion during the made-up process of C++0x and before as to whether templates can be used to copy an object of a class to its own class type. The committee just recently figured they want to stop the confusion about it and allow such a thing. VS2010 seems to reflect that decision.