How to pretty print the name of a template parameter at compile time - c++

The question is rather simple: how to pretty print the name of a template parameter in a C++ class and assign it to a class variable at compile time ?
It seems that both typeinfo (typeid) and boost::typeindex must be evaluated at runtime or as least some part of them. This apparently does not allow the compiler to completely solve a constexpr containing a call to one of this function.
template<typename T>
class X
{
public:
static const char * name = /* SOME C++ code transforming T in a string (either std::string or char */
};
What am I missing ?
Is it only possible to generate a name at runtime ? In that case, does I really need an instantiated object ? It doesn't seem right to me, because the following perfectly work without any instance:
#include <iostream>
#include <string>
#include <boost/type_index.hpp>
using namespace std;
template<class T>
class X
{
public:
static std::string name()
{
return boost::typeindex::type_id<T>().pretty_name();
}
};
struct foobar {};
int main()
{
cout << X<int>::name() << endl;
cout << X<foobar>::name()<< endl;
}
So instead of having name() as a class method, I'd like to have it as a class variable.

I think, it is possible to use custom Type Traits. Please see the next example:
#include <iostream>
#include <string>
using namespace std;
//Using stub type traits
template <class T>
struct TypeTraits;
//your TypeTraits for specific types...
template<>
struct TypeTraits<int>
{
constexpr static const char *name = "int";
};
template<class T>
class X
{
public:
constexpr static const char * name = TypeTraits<T>::name;
};
struct foobar {};
//TypeTraits for custom foobar
template<>
struct TypeTraits<foobar>
{
constexpr static const char *name = "foobar";
};
int main()
{
//Now you can use static member here
cout << X<int>::name << endl;
cout << X<foobar>::name<< endl;
}
Also TypeTraits can be used (and expanded) for other purposes.

Related

Use of incomplete types with std::variant

Suppose I have next code, that is used for simply storing reference/pointer to objects of types A, B or C. I actually don't need complete types.
Now i have the following solution, where I need a lot of #include bloat.
Header:
using MyVariant = std::variant<class A, class B, class C, ...>;
class Holder {
public:
Holder(MyVariant &&TheValue);
const MyVariant &GetValue();
private:
std::unique_ptr<MyVariant> Value;
};
Source file:
#include "A.hpp"
#include "B.hpp"
#include "C.hpp"
Holder::Holder(MyVariant &&TheValue)
: Value(std::make_unique<MyVariant>(std::move(TheValue)) {}
const MyVariant &Holder::GetValue { return Value; }
How I can implement the same semantics without all instantiated types as std::variant template parameters / dynamic memory allocation / dynamic polymorphism?
As others have pointed out the specifications seem a little contradicting.
I can only think of variable template arguments, to achieve not having to specify all possible classes for the Holder class.
Example
#include <iostream>
#include <memory>
#include <variant>
// h
template<typename ...T>
class Holder {
using variant = std::variant<T...>;
public:
Holder(variant &&TheValue)
:Value(std::make_unique<variant>(std::move(TheValue)))
{
};
template<typename TARGET>
const TARGET &GetValue() const {
return std::get<TARGET>(*Value);
};
private:
std::unique_ptr<variant> Value;
};
// main.cpp testing
int main() {
auto a = Holder<int, float>(5);
const auto v = a.GetValue<int>();
std::cout << "holding int: " << v << std::endl;
a = Holder<int, float>(5.5f);
const auto v2 = a.GetValue<float>();
std::cout << "holding float: " << v2 << std::endl;
}
I think at that point it looks like a rather redundant class though.

Determine whether a type exists without feature-test macro

I'd like to determine whether a type exists without using a feature-test macro. Here's the idea using a macro:
namespace real
{
struct foo final { static constexpr const char* name = "real::foo"; };
}
#define real_foo_ 314
struct my_foo final { static constexpr const char* name = "my_foo"; };
namespace real
{
#if !real_foo_
using foo = my_foo;
#endif
}
That is, real::foo should to the "real" foo if it exists, otherwise my_foo will be used; subsequent code uses real::foo w/o knowing or caring whether it's the actual version or the replacement.
Achiving the same template meta-programming seems to be the right idea:
#include <type_traits>
namespace real
{
struct bar final { static constexpr const char* name = "real::bar"; };
}
struct my_bar final { static constexpr const char* name = "my_bar"; };
// https://devblogs.microsoft.com/oldnewthing/20190710-00/?p=102678
template<typename, typename = void>
constexpr bool is_type_complete_v = false;
template<typename T>
constexpr bool is_type_complete_v<T, std::void_t<decltype(sizeof(T))>> = true;
namespace real { struct bar; }
namespace real
{
using bar = std::conditional_t<is_type_complete_v<real::bar>, real::bar, my_bar>;
}
The above works as shown:
#include <iostream>
int main()
{
real::foo foo;
std::cout << foo.name << "\n";
real::bar bar;
std::cout << bar.name << "\n";
}
But removing the actual definition (not the forward) of real::bar causes compiler errors:
namespace real
{
//struct bar final { static constexpr const char* name = "real::bar"; };
}
error C2371: 'real::bar': redefinition; different basic types
message : see declaration of 'real::bar'
error C2079: 'bar' uses undefined struct 'real::bar'
Is there a way to make real::bar work like real::foo without relying on a feature-test macro? Note that as with real::foo, the name of real::bar can't be changed (e.g., to real::really_bar).
(Actual use case: C++14/C++17/C++20 library features implemented in C++11; once client code using std::filesystem::path has been written, it shouldn't have to change.)
Compiler complains on your code because you are trying to create two entities with same name. Consider changing
namespace real
{
struct bar final { static constexpr const char* name = "real::bar"; };
}
to something like
namespace real
{
struct absolutely_bar final { static constexpr const char* name = "real::bar"; };
}
...
namespace real { struct absolutely_bar; }
namespace real
{
using bar = std::conditional_t<is_type_complete_v<real::absolutely_bar>, real::absolutely_bar, my_bar>;
}
PS: creating such aliases is usually a bad pattern since it's not obvious.

namespace specialization in template class

I have two different namespaces that implement identical methods and classes in two different ways. I am writing a class that used this methods and classes to do something, I was wondering if there was a way to declare the namespace without partial specialization as below:
#include <string>
#include <iostream>
namespace one
{
int test()
{
return 1;
}
}
namespace two
{
int test()
{
return 2;
}
}
enum names : int
{
first = 1,
second = 2
};
template <names>
struct base_class;
template <>
struct base_class<names::first>
{
using namespace ::one;
};
template <>
struct base_class<names::second>
{
using namespace ::two;
};
template <names ns>
struct delcare_namespace : public base_class<ns>
{
delcare_namespace()
{
std::cout << test() << "\n";
}
};
for the code above, I get
test’ was not declared in this scope
using namespace is not allowed in class scope, nor is namespace alias. I don't think you can do a specialization that would somehow inject the namespace.
It's not exactly the same, but if it's an option to declare all the functions you need from that namespace in the specialization, you can make the function pointer as a member of that specialization:
template <names>
struct base_class;
template <>
struct base_class<names::first>
{
static constexpr auto test = &one::test;
};
template <>
struct base_class<names::second>
{
static constexpr auto test = &two::test;
};
template <names ns>
struct delcare_namespace : public base_class<ns>
{
delcare_namespace()
{
std::cout << this->test() << "\n";
}
};
I was wondering if there was a way to declare the namespace
Unfortunately, I don't think it's possible inside a class/struct and inheriting it.
is there a work-around for this ?
The best I can imagine (if you can heavily modify your code) is transform your two namespaces in two different classes or structs, so the functions become methods (maybe static methods)
struct baseOne // former namespace one
{
static int test ()
{ return 1; }
};
struct baseTwo // former namespace two
{
static int test ()
{ return 2; }
};
so you can pass the base class (former namespace) as template parameter and inherit from it
template <typename B>
struct foo : public B
{
foo ()
{ std::cout << B::test() << "\n"; }
};
The following is a full working example
#include <string>
#include <iostream>
struct baseOne // former namespace one
{
static int test ()
{ return 1; }
};
struct baseTwo // former namespace two
{
static int test ()
{ return 2; }
};
template <typename B>
struct foo : public B
{
foo ()
{ std::cout << B::test() << "\n"; }
};
int main ()
{
foo<baseOne> f1; // print 1
foo<baseTwo> f2; // print 2
}
If the use of the B:: before the method names is annoying for you, you can transform the static methods inside the bases structs in ordinary methods or add directives as
using B::test;
inside foo.

How to use std::function as a template

I am new to the std::function concept.
I need to use std::function in following way
I have a class as follows
class A(string ,bool, string, std::function<void()>)
here the std::function<void()> should take different parameters from different objects.
The parameters will be basically different types of enumerations
for example
1)A a(string ,bool, string, std::function<void(enum xyz)>)
2)A b(string ,bool, string, std::function<void(enum abc)>)
3)A c(string ,bool, string, std::function<void(enum efg)>)
I want to know how should i structure the std::function in class A so that i can pass different enumerations as parameter to the class A objects
You can pass a template type as the std::function parameter. Here's an example:
#include <iostream>
#include <functional>
#include <string>
template <class T>
class Foo
{
public:
Foo(std::function<void(T)> f) : f_{f} {}
void call(T in) { f_(in); }
private:
std::function<void(T)> f_;
};
int main()
{
Foo<double> fd{[] (double d) { std::cout << d << '\n'; }};
fd.call(34.2);
Foo<std::string> fs{[] (std::string s) { std::cout << s << '\n'; }};
fs.call("Test!");
return 0;
}
Output:
34.2
Test!
After looking at your question, this is how you need to use the function.
#include <iostream>
#include <string>
#include <functional> //Need to include for std::function use
using namespace std;
//Declare the ENUM here.
enum ePat {xyz=1,abc,efg,mno};
enum ePat_second {def=1,ghi,jkl,opq};
//utility function you want to pass to std function
template <typename T>
void print(T e)
{
}
template <typename T>
class A
{
public:
//Constructore with std function as one of the argument
A(string ,bool , string, std::function<void(T)>)
{
}
};
int main()
{
//Declare your std function types.
std::function<void(ePat)> xyz_display = print<ePat>;
std::function<void(ePat_second)> def_display = print<ePat_second>;
//Pass it to the object.
A<ePat> a("abc" ,true, "abc",xyz_display);
A<ePat_second> b("def" ,true, "def",def_display);
}

Using boost::mpl, how can I get how many template classes are not "Empty", and call some macro with this number?

I want to call a macro with some arguments depending on the result of boost::mpl::eval_if (or a similar function) that could give how many template arguments are not empty. Say we have some pseudocode like the following:
struct EmptyType { };
template<class arg1=EmptyType, class arg2=EmptyType, class arg3=EmptyType>
class my_class
{
eval_if<is_not_same<arg1, EmptyType>, FILL_MY_CLASS_DEFINE(1)> else
eval_if<is_not_same<arg2, EmptyType>, FILL_MY_CLASS_DEFINE(2)> else
eval_if<is_not_same<arg3, EmptyType>, FILL_MY_CLASS_DEFINE(3)>;
};
I am trying to fill my class with some content depending on how many arguments are EmptyType. I wonder how such thing can be done in C++03 via Boost.MPL/Preprocessor or some other Boost library?
You don't need preprocessor or mpl. Partial specialization is you need:
Edit This works in C++03, see it live: https://ideone.com/6MaHJ
#include <iostream>
#include <string>
struct EmptyType { };
template<class arg1=EmptyType, class arg2=EmptyType, class arg3=EmptyType>
class my_class
{
// FILL_MY_CLASS_DEFINE(3)
};
template<class arg1, class arg2>
class my_class<arg1,arg2,EmptyType>
{
// FILL_MY_CLASS_DEFINE(2)
};
template<class arg1>
class my_class<arg1,EmptyType,EmptyType>
{
// FILL_MY_CLASS_DEFINE(1)
};
template<>
class my_class<EmptyType,EmptyType,EmptyType>
{
// FILL_MY_CLASS_DEFINE(0)
};
int main(int argc, const char *argv[])
{
my_class<std::string, double, int> a;
my_class<std::string, int> b;
my_class<void> c;
return 0;
}
Are you looking for variadic templates?
#include <tuple>
#include <iostream>
#include <string>
template <typename... Arg>
struct my_class
{
// getting the size of the argument list:
enum { size = sizeof...(Arg) }; // in absense of static fields with initializers...
// demo filling the struct with data:
std::tuple<Arg...> arg_data;
my_class(Arg&&... a) : arg_data(std::forward<Arg>(a)...) { }
};
int main(int argc, const char *argv[])
{
my_class<std::string, int> a("hello world", 42);
std::cout << "size: " << a.size << std::endl;
std::cout << "last: " << std::get<a.size-1>(a.arg_data) << std::endl;
return 0;
}
Output:
size: 2
last: 42
When you have many template arguments, a partial specialization can be impractical and error-prone.
The code below will do what you want, but as it was already mentioned in other answers, it's not always the best way to proceed.
#include <boost/mpl/count_if.hpp>
#include <boost/mpl/not.hpp>
#include <boost/type_traits/is_same.hpp>
using boost::is_same;
using boost::mpl::_;
using boost::mpl::not_;
using boost::mpl::count_if;
#define FILL_MY_CLASS_DEFINE(x) static const int __x__ = x // an example, watch out: no semicolon at the end
struct EmptyType { };
template<class arg1=EmptyType, class arg2=EmptyType, class arg3=EmptyType>
class my_class
{
// count the types which are not equal to EmptyType
static const long NonEmptyCount = count_if<type, not_<is_same<_, EmptyType> > >::value;
// invoke a macro with an argument
FILL_MY_CLASS_DEFINE(NonEmptyCount);
};