Ambiguity issue when deducing function call - c++

I have the following bit of code which has two versions of the function foo. I'd like if a variable is passed for the foo that takes an AVar type to be called otherwise if a const is passed for the AConst version to be called.
#include <iostream>
template <typename T>
struct AConst
{
AConst(T x):t(x){}
const T t;
};
template <typename T>
struct AVar
{
AVar(const T& x):t(x){}
const T& t;
};
template <typename T>
void foo(AConst<T> a) { std::cout << "foo AConst\n"; }
template <typename T>
void foo(AVar<T> a) { std::cout << "foo AVar\n"; }
int main()
{
int i = 2;
foo(1);
foo(i);
return 0;
}
Currently the compiler gives me an ambiguity error. Not sure how to resolve it.
UPDATE: Based on Leonid's answer with a slight modification, here is the following solution which works as required:
template <typename T>
void foo_x(AConst<T> a) { std::cout << "foo AConst\n"; }
template <typename T>
void foo_x(AVar<T> a) { std::cout << "foo AVar\n"; }
template <typename T>
void foo(const T& a) { foo_x(AConst<T>(a));}
template <typename T>
void foo(T& a) { foo_x(AVar<T>(a));}

Compiler can not deduce your T.
To help him, simplify parameter type:
template <typename T>
void foo(const T& a) { AConst<T> aa(a); std::cout << "foo AConst\n"; }
template <typename T>
void foo(T& a) { AVar<T> aa(a); std::cout << "foo AVar\n"; }

Use casting to eliminate ambiguity errors. In this case you could cast "1" as an AConst if I remember right. I don't remember the exact syntax for casting to a template type...maybe something like:
foo( (AConst<int>) 1); .. or something to that effect.

The compiler can't select appropriate function. You may want to declare 2 functions with different names:
template <typename T>
void fooConst(AConst<T> a) { std::cout << "foo AConst\n"; }
template <typename T>
void fooVar(AVar<T> a) { std::cout << "foo AVar\n"; }
Or, you may choose to use functions you have this way:
int main()
{
int i = 2;
foo(AConst<int>(1));
foo(AVar<int>(i));
return 0;
}
In general, you doesn't provide enough information to the compiler. You're the only who knows what instance should be used in the main function. Probably, if you would describe in more details what is the purpose of this code, the solution would be more specific.

You could pass in the full class template to the function like so
#include <iostream>
template <typename T>
struct AConst
{
AConst(T x) :t(x){ std::cout << "AConst\n"; }
const T t;
};
template <typename T>
struct AVar
{
AVar(const T& x) :t(x){ std::cout << "AVar\n"; }
const T& t;
};
template <typename T1>
void foo(T1 a){}
int main()
{
int i = 2;
foo<AConst<int>>(1);
foo<AVar<int>>(i);
return 0;
}

Related

Unify C++ templates for pointers, values and smart pointers

My real example is quite big, so I will use a simplified one. Suppose I have a data-type for a rectangle:
struct Rectangle {
int width;
int height;
int computeArea() {
return width * height;
}
}
And another type that consumes that type, for example:
struct TwoRectangles {
Rectangle a;
Rectangle b;
int computeArea() {
// Ignore case where they overlap for the sake of argument!
return a.computeArea() + b.computeArea();
}
};
Now, I don't want to put ownership constraints on users of TwoRectangles, so I would like to make it a template:
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
// Ignore case where they overlap for the sake of argument!
return a.computeArea() + b.computeArea();
}
};
Usages:
TwoRectangles<Rectangle> x;
TwoRectangles<Rectangle*> y;
TwoRectangles<std::shared_ptr<Rectangle>> z;
// etc...
The problem is that if the caller wants to use pointers, the body of the function should be different:
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
assert(a && b);
return a->computeArea() + b->computeArea();
}
};
What is the best way of unifying my templated function so that the maxiumum amount of code is reused for pointers, values and smart pointers?
One way of doing this, encapsulating everything within TwoRectangles, would be something like:
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
return areaOf(a) + areaOf(b);
}
private:
template <class U>
auto areaOf(U& v) -> decltype(v->computeArea()) {
return v->computeArea();
}
template <class U>
auto areaOf(U& v) -> decltype(v.computeArea()) {
return v.computeArea();
}
};
It's unlikely you'll have a type for which both of those expressions are valid. But you can always add additional disambiguation with a second argument to areaOf().
Another way, would be to take advantage of the fact that there already is a way in the standard library of invoking a function on whatever: std::invoke(). You just need to know the underlying type:
template <class T, class = void>
struct element_type {
using type = T;
};
template <class T>
struct element_type<T, void_t<typename std::pointer_traits<T>::element_type>> {
using type = typename std::pointer_traits<T>::element_type;
};
template <class T>
using element_type_t = typename element_type<T>::type;
and
template<typename T>
struct TwoRectangles {
T a;
T b;
int computeArea() {
using U = element_type_t<T>;
return std::invoke(&U::computeArea, a) +
std::invoke(&U::computeArea, b);
}
};
I actually had a similar problem some time ago, eventually i opted not to do it for now (because it's a big change), but it spawned a solution that seems to be correct.
I thought about making a helper function to access underlying value if there is any indirection. In code it would look like this, also with an example similar to yours.
#include <iostream>
#include <string>
#include <memory>
namespace detail
{
//for some reason the call for int* is ambiguous in newer standard (C++14?) when the function takes no parameters. That's a dirty workaround but it works...
template <class T, class SFINAE = decltype(*std::declval<T>())>
constexpr bool is_indirection(bool)
{
return true;
}
template <class T>
constexpr bool is_indirection(...)
{
return false;
}
}
template <class T>
constexpr bool is_indirection()
{
return detail::is_indirection<T>(true);
}
template <class T, bool ind = is_indirection<T>()>
struct underlying_type
{
using type = T;
};
template <class T>
struct underlying_type<T, true>
{
using type = typename std::remove_reference<decltype(*(std::declval<T>()))>::type;
};
template <class T>
typename std::enable_if<is_indirection<T>(), typename std::add_lvalue_reference<typename underlying_type<T>::type>::type>::type underlying_value(T&& val)
{
return *std::forward<T>(val);
}
template <class T>
typename std::enable_if<!is_indirection<T>(), T&>::type underlying_value(T& val)
{
return val;
}
template <class T>
typename std::enable_if<!is_indirection<T>(), const T&>::type underlying_value(const T& val)
{
return val;
}
template <class T>
class Storage
{
public:
T val;
void print()
{
std::cout << underlying_value(val) << '\n';
}
};
template <class T>
class StringStorage
{
public:
T str;
void printSize()
{
std::cout << underlying_value(str).size() << '\n';
}
};
int main()
{
int* a = new int(213);
std::string str = "some string";
std::shared_ptr<std::string> strPtr = std::make_shared<std::string>(str);
Storage<int> sVal{ 1 };
Storage<int*> sPtr{ a };
Storage<std::string> sStrVal{ str };
Storage<std::shared_ptr<std::string>> sStrPtr{ strPtr };
StringStorage<std::string> ssStrVal{ str };
StringStorage<const std::shared_ptr<std::string>> ssStrPtr{ strPtr };
sVal.print();
sPtr.print();
sStrVal.print();
sStrPtr.print();
ssStrVal.printSize();
ssStrPtr.printSize();
std::cout << is_indirection<int*>() << '\n';
std::cout << is_indirection<int>() << '\n';
std::cout << is_indirection<std::shared_ptr<int>>() << '\n';
std::cout << is_indirection<std::string>() << '\n';
std::cout << is_indirection<std::unique_ptr<std::string>>() << '\n';
}

Branch on a template parameter in function?

I have a templated function, and at one point I would like to have different code depending on the template parameter:
template <typename T>
void function(const T &param) {
// generic code here...
// pseudo-code:
if constexpr isinstance(param, Banana) {
param.peel();
} else if constexpr isinstance(param, Apple) {
// do nothing, Apple has no method `peel`
}
}
I don't want to specialize the whole function, since most of the code is shared. The statement I want to insert is acutally a temporary debugging measure. I know the correct thing would be to create a overloaded function doPeel and call that instead:
void doPeel(const Banana &param) { param.peel(); }
void doPeel(const Apple &param) {}
But I'm curious, is there a way to tell at compile time, in a function, what (template specialization) type a given variable is... in order to use statements that only compile for one type?
I wonder if something like that is possible with constexpr - or does the compiler enforce types in a discarded branch? I also tried making up something with lambdas - defining lambdas for both cases and only calling one, but I could not find a way to do it. Any ideas?
There is if constexpr in C++17:
template<typename T>
void foo(T const& t)
{
if constexpr(is_same<decay_t<T>, int>::value) {
cout << __PRETTY_FUNCTION__ << " " << t * 2 << endl;
} else {
cout << __PRETTY_FUNCTION__ << endl;
}
}
live demo
In C++14 you could hack something like this:
template<typename T>
void foo(T const& t)
{
conditional_eval<is_same<decay_t<T>, int>>([=](auto){
cout << __PRETTY_FUNCTION__ << " " << t * 2 << endl;
},[](auto){
cout << __PRETTY_FUNCTION__ << endl;
});
}
With conditional_eval defined as:
template<typename IfTrue, typename IfFalse>
void conditional_eval_impl(std::true_type, IfTrue&& t, IfFalse&&) {
t(0);
}
template<typename IfTrue, typename IfFalse>
void conditional_eval_impl(std::false_type, IfTrue&&, IfFalse&& f) {
f(0);
}
template<typename Tag, typename IfTrue, typename IfFalse>
void conditional_eval(IfTrue&& t, IfFalse&& f) {
conditional_eval_impl(Tag{}, std::forward<IfTrue>(t), std::forward<IfFalse>(f));
}
live demo
In C++14 you could emulate if constexpr using generic lambda e.g. by:
#include <type_traits>
#include <iostream>
template <bool B>
struct constexpr_if {
template <class Lambda, class T>
static void then(Lambda l, T&& value) { }
};
template <>
struct constexpr_if<true> {
template <class Lambda, class T>
static void then(Lambda l, T&& value) {
l(std::forward<T>(value));
}
};
struct Banana {
void peel() const {
std::cout << "Banana::peel" << std::endl;
}
};
struct Apple {
};
template <typename T>
void function(const T &param) {
constexpr_if<std::is_same<T, Banana>::value>::then([&](auto &p){
p.peel();
}, param);
}
int main() {
function(Banana{});
function(Apple{});
}

What's the right way to fix this template resolution ambiguity?

Suppose I've written:
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
void foo() { std::cout << "T is integral." << std::endl; }
template <typename T>
void foo() { std::cout << "Any T." << std::endl; }
int main() { foo<short>(); }
When I compile this, I get an error about the ambiguity of the call (and no error if, say, I replace short with float). How should I fix this code so that I get the upper version for integral types and lower version otherwise?
Bonus points if your suggestion scales to the case of multiple specialized versions of foo() in addition to the general one.
I like Xeo's approach for this problem. Let's do some tag dispatch with a fallback. Create a chooser struct that inherits from itself all the way down:
template <int I>
struct choice : choice<I + 1> { };
template <> struct choice<10> { }; // just stop somewhere
So choice<x> is convertible to choice<y> for x < y, which means that choice<0> is the best choice. Now, you need a last case:
struct otherwise{ otherwise(...) { } };
With that machinery, we can forward our main function template with an extra argument:
template <class T> void foo() { foo_impl<T>(choice<0>{}); }
And then make your top choice integral and your worst-case option... anything:
template <class T, class = std::enable_if_t<std::is_integral<T>::value>>
void foo_impl(choice<0> ) {
std::cout << "T is integral." << std::endl;
}
template <typename T>
void foo_impl(otherwise ) {
std::cout << "Any T." << std::endl;
}
This makes it very easy to add more options in the middle. Just add an overload for choice<1> or choice<2> or whatever. No need for disjoint conditions either. The preferential overload resolution for choice<x> takes care of that.
Even better if you additionally pass in the T as an argument, because overloading is way better than specializing:
template <class T> struct tag {};
template <class T> void foo() { foo_impl(tag<T>{}, choice<0>{}); }
And then you can go wild:
// special 1st choice for just int
void foo_impl(tag<int>, choice<0> );
// backup 1st choice for any integral
template <class T, class = std::enable_if_t<std::is_integral<T>::value>>
void foo_impl(tag<T>, choice<0> );
// 2nd option for floats
template <class T, class = std::enable_if_t<std::is_floating_point<T>::value>>
void foo_impl(tag<T>, choice<1> );
// 3rd option for some other type trait
template <class T, class = std::enable_if_t<whatever<T>::value>>
void foo_impl(tag<T>, choice<2> );
// fallback
template <class T>
void foo_impl(tag<T>, otherwise );
One more option using tag dispatch (C++11):
#include <iostream>
void foo_impl(std::false_type) {
std::cout << "Any T." << std::endl;
}
void foo_impl(std::true_type) {
std::cout << "T is integral." << std::endl;
}
template <typename T>
void foo() {
foo_impl(std::is_integral<typename std::remove_reference<T>::type>());
//foo_impl(std::is_integral<typename std::remove_reference_t<T>>()); // C++14
}
int main() {
foo<short>(); // --> T is integral.
foo<short&>(); // --> T is integral.
foo<float>(); // --> Any T.
}
Borrowed from Scott Meyers Effective Modern C++ item 27.
One way:
template <typename T, typename std::enable_if_t<std::is_integral<T>::value>* = nullptr>
void foo() { std::cout << "T is integral." << std::endl; }
template <typename T, typename std::enable_if_t<not std::is_integral<T>::value>* = nullptr>
void foo() { std::cout << "Any T." << std::endl; }
Another way is to defer to a template function object:
template<class T, typename = void>
struct foo_impl
{
void operator()() const {
std::cout << "Any T." << std::endl;
}
};
template<class T>
struct foo_impl<T, std::enable_if_t<std::is_integral<T>::value>>
{
void operator()() const {
std::cout << "T is integral." << std::endl;
}
};
template<class T>
void foo() {
return foo_impl<T>()();
}
One way to do this is:
template <typename T>
std::enable_if_t<std::is_integral<T>::value, void> foo () {
std::cout << "integral version" << std::endl;
}
template <typename T>
std::enable_if_t<!std::is_integral<T>::value, void> foo () {
std::cout << "general version" << std::endl;
}
with usage:
foo<int> ();
foo<double> ();
struct X {};
foo<X> ();
output is:
integral version
general version
general version
AFAIK, sfinae is applicable to function params so try to add parameter of dependent type with default value
template <typename T>
void foo(typename std::enable_if_t<std::is_integral<T>::value>* = 0)
{ std::cout << "T is integral." << std::endl; }
template <typename T>
void foo(typename std::enable_if_t<!std::is_integral<T>::value>* = 0)
{ std::cout << "Any T." << std::endl; }

Tag dispatching example in C++

I started to play with the example available here and modified it to get the following code:
#include <iostream>
struct slow_tag {};
struct fast_tag {};
template <typename T>
struct traits
{
typedef slow_tag tag;
};
template <>
struct traits<int>
{
typedef fast_tag tag;
};
template <typename T>
void work_dispatch(const slow_tag)
{
std::cout << "Slow function" << std::endl;
}
template <typename T>
void work_dispatch(const fast_tag)
{
std::cout << "Fast function" << std::endl;
}
template <typename T>
void work_dispatch(const T)
{
work_dispatch(typename traits<T>::tag());
}
int main()
{
std::cout << "Starting my program" << std::endl;
work_dispatch(3.0);
work_dispatch(3);
}
Can anyone explain my why this particular (modified) example crashes with a segmentation fault? If I compile it I don't get any type of warning even when using -Wall with g++ 4.x.
I'll reduce your code to a simple example:
#include <iostream>
template <typename T>
void work_dispatch(double)
{
std::cout << "Slow function" << std::endl;
}
int main()
{
work_dispatch(3.0);
}
Compile error:
main.cpp:11:3: error: no matching function for call to 'work_dispatch'
work_dispatch(3.0);
^~~~~~~~~~~~~
main.cpp:4:6: note: candidate template ignored: couldn't infer template argument 'T'
void work_dispatch(double)
^
1 error generated.
In other words you can't call this template
template <typename T>
void work_dispatch(double)
{
std::cout << "Slow function" << std::endl;
}
with
work_dispatch(3.0);
since there is no way you can deduce the type T, nor you're passing it explicitly. Therefore you have a stack overflow due to an infinite recursion:
template <typename T>
void work_dispatch(const T) <----------------|
{ | This ends up calling itself
work_dispatch(typename traits<T>::tag()); -|
}
To fix your code the easiest solution is to provide the type yourself
template <typename T>
void work_dispatch(const T)
{
work_dispatch<T>(typename traits<T>::tag());
}
Example
With signature
template <typename T>
void work_dispatch(const slow_tag);
T cannot be deduced, so you have to provide it in the call
template <typename T>
void work_dispatch(const T)
{
work_dispatch<T>(typename traits<T>::tag());
}
As currently
template <typename T>
void work_dispatch(const T)
{
work_dispatch(typename traits<T>::tag());
}
call itself recursively until the crash.
template <typename T>
void work_dispatch(const slow_tag)
{
std::cout << "Slow function" << std::endl;
}
The compiler cannot figure out what T should be in this function, so it is not considered in the overload resolution.
And you don't get any error, because "Substitution Failure Is Not An Error".
Running you program under Valgrind shows that you have a stack overflow caused by this line:
work_dispatch(3.0);
which executes this line: work_dispatch(typename traits<T>::tag()); over and over again (causing stack overflow).
EDIT: I think what you are trying to do here should be possible with the following fixes:
#include <iostream>
struct slow_tag {};
struct fast_tag {};
template <typename T>
struct traits {
typedef slow_tag tag;
};
template <>
struct traits<int> {
typedef fast_tag tag;
};
template <typename T>
void work_dispatch(const T& val, const slow_tag& st) {
std::cout << "Slow function" << std::endl;
}
template <typename T>
void work_dispatch(const T& val, const fast_tag& ft) {
std::cout << "Fast function" << std::endl;
}
template <typename T>
void work_dispatch(const T& val) {
work_dispatch(val, typename traits<T>::tag());
}
int main() {
std::cout << "Starting my program" << std::endl;
work_dispatch(3.0);
work_dispatch(3);
}
That is, you should:
Do the dispatch providing value (I have also changed the function argument to T reference)
Pass the value to both templated function launched from the dispatch function.

function template does not recognize lvalue

I have a problem in my code
Here is simplified version of it :
#include <iostream>
class A
{
public :
template <class T>
void func(T&&)//accept rvalue
{
std::cout<<"in rvalue\n";
}
template <class T>
void func(const T&)//accept lvalue
{
std::cout<<"in lvalue\n";
}
};
int main()
{
A a;
double n=3;
a.func(n);
a.func(5);
}
I expect the output to be :
in lvalue
in rvalue
but it is
in rvalue
in rvalue
why ?!
template <class T> void func(T&&) is universal reference forwarding reference.
To test what you want, try: (Live example)
template <typename T>
class A
{
public:
void func(T&&)//accept rvalue
{
std::cout<<"in rvalue\n";
}
void func(T&)//accept lvalue
{
std::cout<<"in lvalue\n";
}
};
int main()
{
A<double> a;
double n = 3;
a.func(n);
a.func(5.);
}
To build on Jarod42's fine answer, if you want to keep the design of having a primary function template, you can decide based on the deduced type of the universal reference parameter:
#include <iostream>
#include <type_traits>
struct A
{
template <typename T> // T is either U or U &
void func(T && x)
{
func_impl<T>(std::forward<T>(x));
}
template <typename U>
void func_impl(typename std::remove_reference<U>::type & u)
{
std::cout << "lvalue\n";
}
template <typename U>
void func_impl(typename std::remove_reference<U>::type && u)
{
std::cout << "rvalue\n";
}
};
I think the surprise comes from the way the template argument are deduced. You'll get what you expect if you write:
a.func<double>(n);