I want to make a function called debug that outputs some info about objects. My system contains objects of many different types; some of them contain other objects.
using namespace std; // for brevity
struct dog {string name;};
struct human {string name; string address;};
struct line {list<human*> contents;};
struct pack {vector<dog*> contents;};
I want the function to output the member name of the argument if it has one, or debug the contents member of the argument if it has one.
I came up with the following code:
template <class T>
void debug(T object) // T here is a simple object like dog, human, etc
{
cout << object.name.c_str() << '\n';
}
// A helper function, not really important
template <class T>
void debug_pointer(T* object)
{
debug(*object);
}
void debug(pack object)
{
for_each(object.contents.begin(), object.contents.end(), debug_pointer<dog>);
}
void debug(line object)
{
for_each(object.contents.begin(), object.contents.end(), debug_pointer<human>);
}
Here, the code for pack and line is nearly identical! I would like to avoid writing the same code several times:
struct line {list<human*> contents; typedef human type;};
struct pack {vector<dog*> contents; typedef dog type;};
template <class T>
void debug(T object) // T here is a compound object (having contents)
{
for_each(object.contents.begin(), object.contents.end(), debug_pointer<T::type>);
}
But this syntax conflicts with the function template for the "simple" objects (has the same signature).
How can i rewrite my code? I don't want to rewrite the first part (declarations for dog, human, etc) because that part of my program is already very complicated, and adding stuff (base classes, member functions, etc) to it just for debugging seems out of place.
The basic code could look like this:
template <typename T> void debug(T const & x)
{
debug_helper<T, has_name<T>::value>::print(x);
}
We need a helper class:
template <typename, bool> struct debug_helper;
template <typename T> struct debug_helper<T, true>
{
static void print(T const & x) { /* print x.name */ }
};
template <typename T> struct debug_helper<T, false>
{
static void print(T const & x) { /* print x.content */ }
};
Now we just need a SFINAE trait class has_name<T>, and a mechanism to print containers. Both those problems are solved almost verbatim in the pretty printer code.
Make the container a template parameter as well:
template <template <typename> class Container, typename T>
void debug(Container<T> object)
{
for_each(object.contents.begin(), object.contents.end(), debug_pointer<T>);
}
BTW, most of the cases you may want to pass by const reference instead of by value (which requires copying the whole vector/list):
template <template <typename> class Container, typename T>
void debug(const Container<T>& object)
If C++11 can be used, you could use decltype to determine the T from the contents:
template <typename T>
void debug(const T& object)
{
typedef decltype(*object.contents.front()) T;
for_each(object.contents.begin(), object.contents.end(), debug_pointer<T>);
}
GCC also has typeof when C++11 cannot be used.
Using C++11, decltype and SFINAE make things easy :)
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <algorithm>
struct dog { std::string name; };
struct human { std::string name; std::string address; };
struct line { std::list<human*> contents; };
struct pack { std::vector<dog*> contents; };
template <typename T>
auto debug(T const& t) -> decltype(t.name, void(0)) {
std::cout << t.name << '\n';
}
template <typename T>
auto debug(T const* t) -> decltype(t->name, void(0)) {
if (t != 0) std::cout << t->name << '\n';
}
struct Debugger {
template <typename T>
void operator()(T const& t) { debug(t); }
};
template <typename C>
auto debug(C const& c) -> decltype(c.contents, void(0)) {
typedef decltype(c.contents) contents_type;
typedef typename contents_type::value_type type;
std::for_each(c.contents.begin(), c.contents.end(), Debugger());
}
int main() {
dog dog1 = { "dog1" }, dog2 = { "dog2" };
human h1 = { "h1" }, h2 = { "h2" };
line l; l.contents.push_back(&h1); l.contents.push_back(&h2);
debug(l);
}
In action at ideone this yields:
h1
h2
as expected :)
Without C++11, it requires some little craft but the principle remains the same, using boost::enable_if you need to create a structure that will provoke a compilation error based on the presence and accessibility of name and contents.
Of course, it would all easier if you simply hooked up the methods in the structures themselves :)
You can use SFINAE to select the overload being used.
I forget the exact details, but you can use it to detect the presence of a "contents" member or a "name" member and then overload based on that.
Related
It's a pity that there are some APIs provided by others that are out of my control and the said APIs return the same type(i.e. uint8_t other than the enum type).
But the meaning is different when the same value is returned by the different APIs. I hope to use overloading to convert the returned value to readable strings.
However, as per this answer, which says:
a typedef is just another name for the same type. But you can only overload on different types.
I thought and thought, and I found a solution. But I think there must be a better one. How?
But when I finish the code snippet below. I am more confused.
Since Demo::Foo::SampleType and Demo::Bar::SampleTypeare the same thing, so the overloading should not work. But the code snippet works well! What a surprise!
Here is the demo code snippet for my solution:
#include <iostream>
#include <map>
namespace Demo
{
class Foo
{
public:
using SampleType = uint8_t;
SampleType GetFooData(){return SampleType{1};}
};
class Bar
{
public:
using SampleType = uint8_t;
SampleType GetBarData(){return SampleType{2};}
};
}
//////////////////code above is provided by others/////////////
template <typename T>
void FindAndPrint(const T& val, const std::map<T, std::string>& mp)
{
auto itr = mp.find(static_cast<T>(val));
if(itr != mp.end())
{
std::cout << itr->second;
}
else
{
std::cout << "can't classify";
}
std::cout << std::endl;
}
template <typename ServiceName>
void Print(const typename ServiceName::SampleType& data);
template <>
void Print<Demo::Foo>(const typename Demo::Foo::SampleType& data)
{
enum class Color
{
Blue = 1,
Red = 2,
};
std::map<Color, std::string> mp ={
{Color::Blue, "Blue"},
{Color::Red, "Red"},
};
FindAndPrint(static_cast<Color>(data), mp);
return;
}
template <>
void Print<Demo::Bar>(const typename Demo::Foo::SampleType& data)
{
// similar code like above
// When I write this line, I start to realize my solution is wrong since `Demo::Foo::SampleType` and `Demo::Foo::SampleType`are the same thing!
// But, what a surprise! This code snippet compiles and works well. Why?
enum class Animal
{
Dog = 1,
Cat = 2,
};
std::map<Animal, std::string> mp ={
{Animal::Dog, "Dog"},
{Animal::Cat, "Cat"},
};
FindAndPrint(static_cast<Animal>(data), mp);
return;
}
int main()
{
Demo::Foo foo;
Print<Demo::Foo>(foo.GetFooData());
Demo::Bar bar;
Print<Demo::Bar>(bar.GetBarData());
}
What you have is not function overload. It is template specialization. The 3 functions you have:
template <typename ServiceName>
void Print(const typename ServiceName::SampleType& data);
template <>
void Print<Demo::Foo>(const typename Demo::Foo::SampleType& data);
template <>
void Print<Demo::Bar>(const typename Demo::Foo::SampleType& data);
It doesn't really matter how you spell out the parameter type, as long the deduced type is consistent with how you primary template was defined. Which mean you can also write them as:
template<>
void Print<Demo::Foo>(const uint8_t& data);
And the reason Print<Demo::Foo>(...) and Print<Demo::Bar>(...) are considered different functions is because you are providing different template parameters. As long Demo::Foo and Demo::Bar are not the same type, then they are considered 2 different template specialization of your base template.
You can put all the specifics about how to decode the uint8_t in a template class SampleTypeInfo that you specialize for the services. If you do that properly, the Print function can be collapsed to
template <typename ServiceName>
void Print(const typename ServiceName::SampleType& data) {
typedef SampleTypeInfo<ServiceName> Info;
FindAndPrint(Info::decode(data), Info().stringMap);
}
Here is how you can implement SampleTypeInfo:
template <typename T> struct SampleTypeInfo {};
template <typename T>
struct SampleTypeInfoBase {
typedef T SampleType;
static T decode(uint8_t x) {
return static_cast<T>(x);
}
std::map<T, std::string> stringMap;
protected:
void regString(T k, const std::string& v) {
stringMap[k] = v;
}
};
template <>
struct SampleTypeInfo<Demo::Foo> : public SampleTypeInfoBase<Color> {
SampleTypeInfo() {
regString(Color::Blue, "blue");
regString(Color::Red, "red");
}
};
template <>
struct SampleTypeInfo<Demo::Bar> : public SampleTypeInfoBase<Animal> {
SampleTypeInfo() {
regString(Animal::Cat, "cat");
regString(Animal::Dog, "dog");
}
};
Consider this case with multiple (implementation) inheritance with mixin pattern:
#include <string>
#include <iostream>
template <typename... Bases>
struct Overloads : public Bases... {};
struct Human {};
struct Animal {};
struct Named {
std::string name_;
void setName(const std::string& name) {
name_ = name;
}
const std::string& getName() const noexcept { return name_; }
};
template <typename OverloadsType>
struct Actor : public OverloadsType {
Actor() : OverloadsType() {}
template <typename OtherOverloads>
Actor(const Actor<OtherOverloads>& other_actor) {
// ???????
this->setName(other_actor.getName());
}
};
int main() {
Actor<Overloads<Human, Named>> named_human;
named_human.setName("Bob");
std::cout << named_human.getName() << '\n';
Actor<Overloads<Animal, Named>> named_animal;
Actor<Overloads<Animal, Named>> animal_once_a_human (named_human);
std::cout << animal_once_a_human.getName() << '\n';
}
The code works correctly, printing two Bobs: Link
I want two things
Make the conversion operator compiles even when OverloadsType and OtherOverloads aren't derived from Named (this->setName(other_actor.getName()); should be ignored or not compiled at all)
Generalize "transferring" information from (common) base classes, not only name
How can I do this?
Here's a basic blueprint. This can be further refined so that the concept actually checks that getName() return a std::string.
#include <string>
#include <iostream>
template<typename T>
concept has_a_name = requires(T &t) {
{ t.getName() };
};
template<typename T, typename U>
void give_name(const T &t, U &u)
{
}
template<has_a_name T, typename U>
void give_name(const T &t, U &u)
{
u.setName(t.getName());
}
struct tom {
std::string getName() const
{
return "Tom";
}
};
struct jerry {};
struct cartoon {
void setName(const std::string &s)
{
std::cout << s << "\n";
}
template<typename T>
cartoon(const T &t)
{
give_name(t, *this);
}
};
int main()
{
tom Tom;
jerry Jerry;
cartoon mgm{Tom}, mgm2{Jerry};
return 0;
}
As far as generalizing this goes, any possible "generic" way of defining getters and setters will either be even longer than this, or use arcane, cryptic, difficult to read templates that end up expressing very simple operations.
A simple concept that defines each class that implements a particular getter, and a pair of template functions that select a stub or the real deal, via simple overload resolution, is easy to read, understand and follow.
I want two things
Make the conversion operator compiles even when OverloadsType and OtherOverloads aren't derived from Named (this->setName(other_actor.getName()); should be ignored or not compiled at all)
Generalize "transferring" information from (common) base classes, not only name
How can I do this?
So, if the source also has the base class, it should be copied, and otherwise we should use a default constructed instance. This is straightforward.
We can define a function to extract that initializer, a copy of a base if there is one, otherwise a default constructed instance:
template <std::semiregular T, typename U>
constexpr auto extract(const U& u) -> T {
if constexpr (std::derived_from<U, T>) {
return u;
}
else {
return T();
}
}
Then we can use that to initialize the "overloads":
template <typename... Bases>
struct Overloads : public Bases... {
Overloads() = default;
template <typename OtherOverloads>
Overloads(const OtherOverloads& other_overloads) : Bases{extract<Bases>(other_overloads)}... {}
};
Then we can use that logic to initialize the actor:
template <typename OtherOverloads>
Actor(const Actor<OtherOverloads>& other_actor) : OverloadsType(other_actor) {}
See https://godbolt.org/z/ofjPb8x75
Let's say I have the following class:
template <typename T>
class SomeClass : Parent<T>
{
public:
// I have a function such as this one:
T DoSomething(const T &t)
{
return t.DoSomething(some_data);
}
// But `T` might be a pointer, so sometimes I will need something like the following
// instead (which obviously doesn't work as given):
T DoSomething(const T &t)
{
return new T(t->DoSomething(some_data));
}
private:
XYZ some_data;
};
I got stuck in a giant mess of template errors trying to implement this in any semi-nice way possible using template specialization.
In the end I came up with this very ugly solution:
template <typename T>
class SomeClass : Parent<T>
{
public:
T DoSomething(const T &x)
{
return Specializer<T>::Do(this, x);
}
private:
template <typename V>
struct Specializer {
static V Do(SomeClass *me, const V &x)
{
return x.DoSomething(me->some_data);
}
};
template <typename V>
struct Specializer<V*> {
static V* Do(SomeClass *me, const V *&x)
{
return new V(x->DoSomething(me->some_data));
}
};
XYZ some_data;
};
Is there a better way to do this that doesn't involve stuffing this function into a dummy class/struct and passing around my this pointer?
PS: In reality, this has nothing to do with pointers, but rather with different types of containers. Pointers were just an easy example to use here.
You can avoid writing any specializations, and use a type trait like std::is_pointer along with if constexpr to decide what code to execute depending on the whether the type is a pointer type or not:
auto DoSomething(const T &t)
{
if constexpr (std::is_pointer_v<T>)
return new T(t->DoSomething(some_data));
else
return t.DoSomething(some_data);
}
If you don't want to check for whether T is a pointer, but want to check something else, you can still use this pattern by dropping in a suitable replacement for is_pointer.
If you have access to c++20, you can clean up the need for any SFINAE, specializations, or if constexpr by using concepts and constraints instead. This just allows you to define the same function N times with different criteria for its insantiation, which is much more readable IMO.
This is almost the same as the SFINAE approach, but without the need for the awful syntax (no std::declval, decltype, etc). It also doesn't require all implementations to exist in one function definition like the if constexpr approach; all you need is separate function definitions with different requires clauses:
#include <concepts>
...
template <typename T>
class SomeClass : Parent<T>
{
public:
// Work for everything that's not specialized
void DoSomething(const T &t)
{
std::cout << "Basic overload" << std::endl;
}
// Only work for pointers
void DoSomething(const T& t) requires(std::is_pointer_v<T>)
{
std::cout << "Pointer overload" << std::endl;
}
// Only work if T is convertible to SomeType
void DoSomething(const T& t) requires(std::convertible_to<T, SomeType>)
{
std::cout << "Convertible to SomeType overload" << std::endl;
}
private:
XYZ some_data;
};
Live Example
In this approach there are 3 different entries:
The basic fallback for all templates
An implementation that works for any pointer type, and
An implementation that works for any T type that may be convertible to SomeType
What about using SFINAE?
For example
#include <utility>
#include <iostream>
template <typename>
struct Parent
{ };
using XYZ = int;
template <typename T>
class SomeClass : Parent<T>
{
public:
template <typename U = T>
auto DoSomething (T const & t)
-> decltype( std::declval<U>().DoSomething(std::declval<XYZ>()) )
{ std::cout << "ref\n"; return t.DoSomething(some_data); }
template <typename U = T>
auto DoSomething (T const & t)
-> std::remove_reference_t<
decltype( std::declval<U>()->DoSomething(std::declval<XYZ>()),
std::declval<T>() )>
{
using V = std::remove_reference_t<decltype(*t)>;
std::cout << "pnt\n"; return new V(t->DoSomething(some_data));
}
private:
XYZ some_data;
};
struct foo
{
foo (foo*) {}
foo () {}
foo DoSomething (int) const { return {}; }
} ;
int main()
{
SomeClass<foo> sc1;
SomeClass<foo*> sc2;
foo f;
sc1.DoSomething(f);
sc2.DoSomething(&f);
}
I mean: what about enabling the first version if, and only if, T is a type that supports a DoSomething(XYZ) method and enabling the second version if, and only if, T is a pointer of a type that supports a DoSomething(XYZ) method?
I would like to have a general templated function declaration for which I do not know (already) the return type, similar to:
**template <class T> auto getIds() noexcept -> std::vector<Any>;**
The function could then be specialized with several input types, and a return type based on it:
template <> auto getIds<MyClass>() noexcept -> std::vector<decltype(MyClass::id)>
{
// implementation here.
}
And finally call it without to set the return:
auto val = getIds<MyClass>();
Is that possible? How?
Notes:
What I want to avoid is to have to set manually the Id type in the call function:
auto val = getIds<MyClass, decltype(MyClass::id)>(); // Ugly
I also discard any (non based on template) solution like extending all types from a RootMyClass. Is not that these solutions are bad, but they miss the point of this question.
Trying to be a bit clearer:
If I wrote
class MyClass { public: int id1=4;};
template <class T, class Id> auto getIds() -> Id;
template <> auto getIds<MyClass, decltype(MyClass::id1)>() -> decltype(MyClass::id1)
{
return 1;
}
auto main() -> int
{
getIds<MyClass>(); // Do not compile
getIds<MyClass, decltype(MyClass::id1)>(); // Compile but ugly
}
I would like the return type to be implicit, but I did not found a way to achieve that with specializations:
template <class T> getIds() noexcept -> WHICH TYPE?;
You cannot change the return type in a specialization, unfortunately. What you can do is change the return type in different overloads. Obviously. Furthermore, function template specializations are much more complicated than function overloads anyway, so let's do that.
Introduce an empty type wrapper, say:
template <typename T> struct wrapper { };
And forward the default implementation to that (I'm assuming C++14 here, otherwise you could wrap that in decltype() with a trailing return):
template <typename T>
auto getIds() { return getIds(wrapper<T>{}); }
Declare the generic version as:
template <typename T>
void getIds(wrapper<T> );
Don't define it. Then, anytime somebody tries to do:
auto ids = getIds<X>();
If there is no overload, that will simply fail to compile as you cannot assign from void. Then, you can overload as you see fit:
std::vector<decltype(MyClass::id)> getIds(wrapper<MyClass> )
{ ... }
FINAL EXAMPLE:
#include <iostream>
#include <vector>
template <typename T> struct wrapper { };
template <typename T>
auto getIds() -> decltype(getIds(wrapper<T>{}))
{
return getIds(wrapper<T>{});
}
template <typename T>
void getIds(wrapper<T> ) { }
struct MyClass {
int id;
};
std::vector<decltype(MyClass::id)> getIds(wrapper<MyClass> )
{
return {1, 2, 3};
}
int main()
{
for (auto id : getIds<MyClass>()) {
std::cout << id << " ";
}
}
This is actually very similar to Haskell typeclasses, and, surprisingly, works. For real usage I would use functors to allow partial specializations, though.
#include <iostream>
template<typename T>
decltype(T::x) getX(T const& t) { return; }
class A { public: int x; A(int x):x(x){} };
template<> int getX<A>(A const& a) {
return a.x;
}
class B { public: std::string x; B(std::string x):x(std::move(x)){} };
template<> std::string getX<B>(B const& b) {
return b.x;
}
int main() {
A a(42);
B b("43");
std::cout << getX(a) << std::endl;
std::cout << getX(b) << std::endl;
}
As you can see, each specialization has to (can?) provide the return type explicitly. decltype(A::x) (and B::x), respectively) could be used instead if you so prefer.
To make it even more Haskell-ish, you could expect a type tag in the type itself (basically a type family):
template<typename T>
typename T::TypeOfX getX(T const& t) { return; }
And consequently:
class A {
using TypeOfX = int;
TypeOfX someComplexLogicToGetX();
};
Both solutions to the type being instantiated for the actual type, except one gets it from a type of a field, and the other from a direct "type variable".
Hi I was playing around with TMP and was thinking of generating of a class
that looks something like:
template<typename T, typename LogFunc>
class
{
(where LogFunc should be defaulted to "nop" function)
Idea is to have a class that defines some functionality for instances of type T, for example checks if the number is even, and also has the option to log by calling
void memberFunc(T& t)
{
LogFunc(t);
}
or maybe
void memberFunc(T& t)
{
LogFunc lf;
lf(t);
}
Can it be done?
From reading A on SO, lambdas are kind of problematic as templ params.
BTW if somebody cares this is what I tried but it prints out
:(
The problem is that the type of a lambda is a compiler-enforced singleton; it has only one value, which is the lambda itself; furthermore, the type has a deleted constructor. So you can't pass lambdas as part of a template instantiation, even with decltype. But there's nothing stopping you from passing them as constructor arguments.
However, here we run into another problem: constructor arguments are not used to deduce a template instantiation (which is why the standard library provides utilities like make_pair and make_tuple). So we need a templatized factory function.
With all that, the solution is pretty simple:
template<typename T, typename LogFunc>
class Foo {
public:
Foo(const T& t, LogFunc fn) : t_(t), lfn_(fn) {}
//...
private:
T t_;
LogFunc lfn_;
};
struct Noop {
template<typename...A>
void operator()(A...) { };
};
template<typename T, typename LogFunc=Noop>
Foo<T, LogFunc> make_foo(const T& t, LogFunc func=LogFunc()) {
return Foo<T, LogFunc>(t, func);
}
This will not answer directly, but gives a number of hints about what you did.
The LogFunc parameter is a type (not an object), hence
LogFunc(t) creates a temporary LogFunc giving t as parameter (you are in fact calling the LogFunc::LogFunc(T&) contructor).
LogFunc lf; lf(t); creates a stack-living default contructed Logfunc, named lf, and lf(t) calls its LogFunc::operator()(T&) member function.
LogFunc()(t) creates a temporary default-constructed LogFUnc and calls operator()(T&) on it.
About lambdas, they are in fact classes whose constructor takes the captured varaibles, and whose operator() takes the parameters you declare. But they exist only "internaly" to the compiler, and don't have a "name" you can refer to.
What you can do is deduce its type with a decltype, or with a free-function.
Typically a parametric functional class stores a frunction object, initialized at construction.
#include <iostream>
template<class Fn>
class LogFunc
{
public:
LogFunc(Fn f) :fn(f) {}
template<class T>
void memberFunc(T& t)
{ fn(t); }
private:
Fn fn;
};
template<class Fn>
LogFunc<Fn> makeLogFunc(Fn f)
{ return LogFunc<Fn>(f); }
int main()
{
int x=5;
auto lf = makeLogFunc([](int& a){ std::cout << a << std::endl; });
lf.memberFunc(x);
return 0;
}
compile as "g++ -pedantic -Wall -std=c++11", and will ouptut
5
The other answers are all fine, but you can also just pass in a constructor argument with a std::function<T>. That looks like this:
#include <functional>
#include <iostream>
template <typename T> void someOther(T val){
std::cout << "used other "<<val<<std::endl;
}
template <typename T> void noop(T val){
std::cout << "noop "<<val<<std::endl;
}
template<typename T>
struct A{
A(std::function<void(T)> f =noop<T> ) : mf(f){}
void memberFunc(T valx){
mf(valx);
}
std::function<void(T)> mf;
};
int main(){
A<int> aNoop; ;
A<float> aSomeOther{someOther<float>} ;
aNoop.memberFunc(5);
aSomeOther.memberFunc(3.55);
}
An alternative is to use functor classes, like this:
#include <iostream>
template <typename T> struct OtherC{
void operator()(T v){ std::cout <<"other "<<v<<std::endl; };
};
template <typename T> struct NoopC{
void operator()(T){ std::cout << "noop"<<std::endl; };
};
template<typename T, template <typename X> class F = NoopC >
struct A{
static void memberFunc(T valx){ F<T>()(valx); }
};
int main(){
A<int> aNoop;
A<float,OtherC> aSomeOther ;
aNoop.memberFunc(5);
aSomeOther.memberFunc(3.55);
}