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.
Related
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 ¶m) {
// 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 ¶m) { param.peel(); }
void doPeel(const Apple ¶m) {}
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 ¶m) {
constexpr_if<std::is_same<T, Banana>::value>::then([&](auto &p){
p.peel();
}, param);
}
int main() {
function(Banana{});
function(Apple{});
}
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; }
When playing around with good ol' c++ I started wondering whether it is possible to overload a template function based on an enclosing template. At the first layer this looks achievable, however, how can this be done recursively? So that the below pseudo-c++ code
#include <iostream>
#include <vector>
#include <map>
template <typename T> void magic(){
std::cout << "Called magic<T>" << std::endl;
}
template <typename std::vector<T> > void magic(){
std::cout << "Called magic<std::vector<T> >" << std::endl;
magic<T>();
}
template <typename std::map<T,U> > void magic(){
std::cout << "Called magic<std::map<T,U> >" << std::endl;
magic<T>();
magic<U>();
}
int main() {
magic<std::vector<std::map<std::string,std::vector<int> > > >();
}
yields something like:
Called magic<std::vector<T> >
Called magic<std::map<T,U> >
Called magic<T>
Called magic<std::vector<T> >
Called magic<T>
In principle this does not look like it should be impossible because all the type info is available at compile time. The compiler could easily create all required functions since the recursion is bound to stop. And thus the question: Is this possible? If so, how?
Simple specialization should do the trick, but bear in mind that you cannot specialize function templates partially, so you'll need an intermediate class template:
template <typename> void magic();
template <typename T>
struct Impl
{
static void f() { std::cout << "Primary template\n"; }
};
template <typename T, typename A>
struct Impl<std::vector<T, A>>
{
static void f() { std::cout << "A vector\n"; magic<T>(); }
};
template <typename K, typename T, typename P, typename A>
struct Impl<std::map<K, T, P, A>>
{
static void f() { std::cout << "A map\n"; magic<K>(); magic<T>(); }
};
template <typename T> void magic() { Impl<T>::f(); }
You need partial template specialization, that is a template specialization which itself is a template again.
That is not possible with function templates but it is with classes. So the workaround is to create a class template (here called Magic) with the specializations. Within that class, a simple (non-template) function is called.
Then, a function magic forwards to that class in order to hide that "hack":
Live demo of this code snippet
#include <iostream>
#include <vector>
#include <map>
// Forward declaration of the magic function:
template <typename> void magic();
// General case:
template <typename T>
struct Magic {
static void m(){
std::cout << "Called magic<T>" << std::endl;
}
};
// Vector case:
template <typename T>
struct Magic<std::vector<T> > {
static void m(){
std::cout << "Called magic<std::vector<T> >" << std::endl;
magic<T>();
}
};
// Map case:
template <typename T, typename U>
struct Magic<std::map<T,U> > {
static void m(){
std::cout << "Called magic<std::map<T> >" << std::endl;
magic<T>();
magic<U>();
}
};
// Implementation of the magic function:
template <typename T>
void magic() {
std::cout << "Forwarding..." << std::endl;
Magic<T>::m();
}
int main() {
magic<std::vector<std::map<std::string,std::vector<int> > > >();
}
I'm trying to specialize a member function template for two different types of classes as follows:
#include <iostream>
#include <boost/utility/enable_if.hpp>
struct Wibble
{
static const bool CAN_WIBBLE = true;
};
struct Wobble
{
static const bool CAN_WIBBLE = false;
};
struct Foo
{
//template<typename T> // Why isn't this declaration sufficient?
//void doStuff();
template<typename T>
typename boost::enable_if_c<T::CAN_WIBBLE,void>::type
doStuff();
template<typename T>
typename boost::enable_if_c<!T::CAN_WIBBLE,void>::type
doStuff();
};
template<typename T>
typename boost::enable_if_c<T::CAN_WIBBLE,void>::type
Foo::doStuff()
{
std::cout << "wibble ..." << std::endl;
}
template<typename T>
typename boost::enable_if_c<!T::CAN_WIBBLE,void>::type
Foo::doStuff()
{
std::cout << "I can't wibble ..." << std::endl;
}
int main()
{
Foo f;
f.doStuff<Wibble>();
f.doStuff<Wobble>();
}
Whereas GCC 4.8.2 compiles the code, VS .NET 2008 spits out the error message:
error C2244: 'Foo::doStuff' : unable to match function definition to an existing declaration
definition
'boost::enable_if_c<!T::CAN_WIBBLE,void>::type Foo::doStuff(void)'
existing declarations
'boost::enable_if_c<!T::CAN_WIBBLE,void>::type Foo::doStuff(void)'
'boost::enable_if_c<T::CAN_WIBBLE,void>::type Foo::doStuff(void)'
I suggest to use tag dispatching: https://ideone.com/PA5PTg
struct Foo
{
template<bool wibble>
void _doStuff();
public:
template<typename T>
void doStuff()
{
_doStuff<T::CAN_WIBBLE>();
}
};
template<>
void Foo::_doStuff<true>() { std::cout << "wibble ..." << std::endl; }
template<>
void Foo::_doStuff<false>() { std::cout << "I can't wibble ..." << std::endl; }
You can't partially specialize (member) function templates. End of story.
Even if you could, you should have had a SFINAE-friendly primary template. In pseudo code:
template<typename T, typename Enable> void doStuff();
template<typename T> void doStuff<T, typename boost::enable_if_c<T::CAN_WIBBLE,void>::type>()
{ std::cout << "wibble ..." << std::endl; }
template<typename T> void doStuff<T, typename boost::enable_if_c<!T::CAN_WIBBLE,void>::type>()
{ std::cout << "I can't wibble ..." << std::endl; }
You could still use this technique if you are ready class templates (as functors or just types defining non-template methods...).
As a rule of thumb, for function templates, overload resolution provides static polymorphism that removes the need for partial specialization. See
GotW #49 Template Specialization and Overloading
Why Not Specialize Function Templates?
Both by Herb Sutter
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;
}