Some code I have no control over has a number of overloaded functions which accepts different types
i.e.
setValue(int)
setValue(std::string)
setValue(bool)
And I have a template function which would idealy take any one of these types and pass it on to the correct setValue function.
template <class T>
do_something(T value) {
...
setValue(value);
But I get this error
error: call to member function 'SetValue' is ambiguous
Is there anything I can do to work around this problem without copy and pasting my code for each type like the writers of setValue have?
by defining you own SetValue with exact match and forwarding to the correct overload.
void setValue(int i) { setValue(static_cast<double>(i)) }
or (if you have a lot of "setValue" functions with same type) you may help the compiler to choose which overload to use like this:
void setValue(char a);
void setValue(double a);
template <typename T>
struct TypeToUseFor
{
typedef T type;
};
template <>
struct TypeToUseFor<int>
{
typedef double type;
};
template <class T>
void func(T value)
{
setValue(static_cast<typename TypeToUseFor<T>::type>(value));
// setValue(value);
}
int main() {
func(0); // int -> ?
func('0'); // exact match
func(0.0); // exect match
func(0.f); // float -> double
return 0;
}
I have no problems with:
void setValue(int a)
{
}
void setValue(std::string a)
{
}
void setValue(bool a)
{
}
template <class T>
void func(T value)
{
setValue(value);
}
int main()
{
func(5);
}
Here is my run: http://codepad.org/1wq8qd7l
Related
I have a bunch of very similar functions:
void foo1(Obj o) {
bar(o.a);
}
void foo2(Obj2 o) {
bar(o.b);
}
void foo3(Obj3 o) {
bar(o.c);
}
How can I reduce the duplicating of code? Can I do something like:
template<typename T, pointerToMember>
void foo(T o) {
bar(o.pointerToMember);
}
And then create all functions like:
foo<Obj, Obj.x>;
...
?
Yes it is possible to have a pointer to member as template parameter:
#include <string>
struct Obj {
int a,b,c;
};
void bar(int x){}
template<typename T, int (T::*pointerToMember)>
void foo(T o) {
bar(o.*pointerToMember);
}
int main() {
Obj x;
foo<Obj,&Obj::a>(x);
}
However, there are different ways that would make the call less verbose. You could pass the member pointer as parameter to be able to deduce it, that would allow to call it as
foo(x,&Obj::a);
Last not least, you could call bar directly
bar(x.a);
Suppose that a class has a member function which should accept either a double(double) function or a class instance with a "MyStructFunc" public member function as an argument:
#include<functional>
#include <type_traits>
struct Caller
{
// (1.)
double call(std::function<double(double)> func) { return func(1); }
// (2.)
template<typename T>
double call(const T& S) { return S.MyStructFunc(2); }
};
So, for example, we can pass
double myFunc(double x) { return x * x * x; }
or
struct myStruct
{
double MyStructFunc(double x) const { return x * x; }
};
like this:
int main()
{
Caller c;
myStruct ms;
c.call(myFunc);
c.call(ms);
}
Unfortunately, I get an error. Could you please help me make it work? Thank you for your help!
function pointer is not a std::function, so your template method is a better match.
You might use SFINAE to restrict your template method:
// (2.)
template<typename T>
auto call(const T& S) -> decltype(S.MyStructFunc(2)) { return S.MyStructFunc(2); }
Demo
C++ Primer 5th Edition has a snippet of advice at the end of chapter 16.3 (a chapter discussing function template overloading):
Declare every function in an overload set before you define any of the
functions. That way you don’t have to worry whether the compiler will
instantiate a call before it sees the function you intended to call.
So is this telling me that in choosing the candidate and viable functions during overload resolution it is possible the compiler might instantiate a function template that isn't chosen in the end? I tried to see whether this might actually happen:
template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
template <typename T> void test(T*) { }
int main(){
int *q = nullptr;
test(q); //test(T*) should be the best match
}
This program would throw a compiler error if test(T const &) was instantiated in any form, except the program compiles fine as expected. So what kind of compilation mishap is that tip trying to guard me from? When would it ever instantiate a function before it saw the function I was trying to call?
The author is warning you of this:
template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
int main(){
int *q = nullptr;
test(q); //test(T*) will not be matched.
}
template <typename T> void test(T*)
{
}
And these:
template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
template <> void test<int>(int const &);
void test(int *);
int main(){
int *q = nullptr;
test(q); //test(int*) should be the best match
int a;
test(a); // test<int>(int const&) should be the best match
}
template <> void test<int>(int const &)
{
}
void test(int *)
{
}
If you don't provide declarations of
template <> void test<int>(int const &);
void test(int *);
before main, they won't be matched in main.
I've seen plenty of SO questions that is some variation of
template<class T, class... Ts>
T sum(T t, Ts... ts) { return t + sum(ts...); }
// ^ |
// |--------------------------------
// only one visible in
// definition context
template<class T>
T sum(T t) { return t; }
int main() {
sum(1, 2); // doesn't compile
}
(The return type isn't perfect, but you get the idea.)
And then people are surprised when it doesn't compile.
Or, even more fun,
template<class T> void f(T t) { f((int)t); }
void f(int) { /*...*/ }
int main() {
f(1L); // infinite recursion
}
the problem is described briefly as below:
template <typename T>
void display(T data){
if(is_int(T)) // how to check if T is int in this function is_int
printf("<int> %d", data);
if(is_float(T)) // how to check if T is float in this function is_float
printf("<int> %f", data);
if(is_class(T)) // how to check if T is class in this function is_class
data.display();
}
Here suppose that T can be type of int or float or a class.
If I define some variables and want to display their values using the same function:
int a = 10:
float b = 2.7;
A_Class c;
display(a);
display(b);
display(c);
display(new int(3));
display(new float(1.899));
display(new float(1));
I know that in C++, there is one solution for checking int and float(just for the issue of printing), that is to use std::cout, as explained in this question(C++ templates - How to find whether the template type is a basic type or a class).
And using std::is_integral::value doesn't apply for the case like this:
display(new int(3));
display(new float(1.899));
display(new float(1));
because these variables are classes not the basic types. So for this situation, how we judge the type(int or float) of new int(), new float()?
To print the int and float values just provide overloads of display() that take arguments of those types, respectively. For objects that contain a member function named display(), you can use SFINAE to selectively enable the free function form of display()
#include <iostream>
#include <type_traits>
template<typename T>
auto display(T const& t) -> decltype(t.display(), void())
{
std::cout << "display(T const& t)\n";
}
void display(int)
{
std::cout << "display(int)\n";
}
void display(double)
{
std::cout << "display(double)\n";
}
struct foo
{
void display() const
{
std::cout << "foo::display\n";
}
};
struct bar {};
int main()
{
display(10);
display(10.0);
display(foo());
// display(bar()); // doesn't compile
}
Live demo of what happens when you call display(bar());
main.cpp:35:18: error: no matching function for call to 'display(bar)'
display(bar()); // doesn't compile
...
main.cpp:5:49: error: 'const struct bar' has no member named 'display'
You provide the versions directly, check are provided by <type_traits>:
template <typename T>
typename std::enable_if<std::is_same<T, int>::value>::type
display(T data){
printf("<int> %d", data);
}
template <typename T>
typename std::enable_if<std::is_same<T, float>::value>::type
display(T data){
printf("<int> %f", data);
}
template <typename T>
typename std::enable_if<std::is_class<T>::value>::type
display(const T& data){ // you probably don't want to copy the argument
data.display();
}
One way to achieving is using numeric limits. This is however, to check if it is an integer or a floating point number.
You could do the following:
#include<limits>
template <typename T>
void display(T data){
if(std::numeric_limits<T>::is_signed) // how to check if T is int in this function is_int
printf("<int> %d", data);
else // how to check if T is float in this function is_float
printf("<int> %f", data);
}
I have this functor:
struct functor
{
template<class T> void operator()(T value) // (*)
{
// process the value
}
template<> void operator()<const wchar_t *>(const wchar_t *value) // (**)
{
if (value)
{
// process the value
}
}
template<> void operator()<const char *>(const char *value) // (**)
{
if (value)
{
// process the value
}
}
template<> void operator()<wchar_t *>(wchar_t *value) // (**)
{
if (value)
{
// process the value
}
}
template<> void operator()<char *>(char *value) // (**)
{
if (value)
{
// process the value
}
}
};
As you can see, I have 4 identical template specializations. Is there a technique to specify all of them once, meaning somehow to partition all the possible types into the main group (*) and the specialized one (**)?
Thanks.
EDIT
Oops, fixed some typos.
You can get away with a simpler scheme - overloading!
template<class T>
void foo(T value){ // general
// ...
}
template<class T>
void foo(T* value){ // for pointers!
if(value)
foo(*value); // forward to general implementation
}
Also, I'd recommend to make the parameter a reference - const if you don't need to modify it (or maybe both, depending on what you actually need to do):
template<class T>
void foo(T& value){ // general, may modify parameter
// ...
}
template<class T>
void foo(T const& value){ // general, will not modify parameter
// ...
}
If you want to have a special implementation for a certain set of types (i.e., one implementation for the whole set), traits and tag dispatching can help you:
// dispatch tags
struct non_ABC_tag{};
struct ABC_tag{};
class A; class B; class C;
template<class T>
struct get_tag{
typedef non_ABC_tag type;
};
// specialization on the members of the set
template<> struct get_tag<A>{ typedef ABC_tag type; };
template<> struct get_tag<B>{ typedef ABC_tag type; };
template<> struct get_tag<C>{ typedef ABC_tag type; };
// again, consider references for 'value' - see above
template<class T>
void foo(T value, non_ABC_tag){
// not A, B or C ...
}
template<class T>
void foo(T value, ABC_tag){
// A, B, or C ...
}
template<class T>
void foo(T value){
foo(value, typename get_tag<T>::type()); // dispatch
}
Bottom line is, you'll need atleast some amount of duplication (tags, overloads, ...) if you want to group types that have nothing in common.
You mean like this?
struct functor
{
template<class T> void operator()(T value)
{
// process the value
}
template<class T> void operator()(T* value) // overload, not specialization
{
if (value) {
// process the value
}
}
};
http://ideone.com/P8GLp
If you want only those types, something else
struct functor
{
protected:
template<class T> void special(T* value) // overload, not specialization
{
if (value) {
// process the value
}
}
public
template<class T> void operator()(T value)
{
// process the value
}
void operator()(char* value) {special(value);}
void operator()(wchar_t* value) {special(value);}
void operator()(const char* value) {special(value);}
void operator()(const wchar_t* value) {special(value);}
};