Currently I have:
template struct typename_struct {
static char const* name() {
return (std::string(typename_struc
You could use something like this. Everything happens at compile time. Specialize base_typename_struct to define your primitive types.
template <const char* str, int len, char... suffix>
struct append {
static constexpr const char* value() {
return append<str, len-1, str[len-1], suffix...>::value();
}
};
template <const char* str, char... suffix>
struct append<str, 0, suffix...> {
static const char value_str[];
static constexpr const char* value() {
return value_str;
}
};
template <const char* str, char... suffix>
const char append<str, 0, suffix...>::value_str[] = { suffix..., 0 };
template <typename T>
struct base_typename_struct;
template <>
struct base_typename_struct<int> {
static constexpr const char name[] = "int";
};
template <typename T, char... suffix>
struct typename_struct {
typedef base_typename_struct<T> base;
static const char* name() {
return append<base::name, sizeof(base::name)-1, suffix...>::value();
}
};
template <typename T, char... suffix>
struct typename_struct<T*, suffix...>:
public typename_struct<T, '*', suffix...> {
};
int main() {
cout << typename_struct<int****>::name() << endl;
}
I'm not sure of what you're searching for but I believe you're interested in a combination of typeid and name-demangling (which compiler are you using?)
In gcc it would be something like
#include<iostream>
#include <string>
#include <typeinfo>
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
using namespace std;
std::string demangle(const char* name) {
int status = -4; // some arbitrary value to eliminate the compiler warning
// enable c++11 by passing the flag -std=c++11 to g++
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status==0) ? res.get() : name ;
}
template <typename T> struct typename_struct {
static std::string name() {
std::string typeName = typeid(T).name();
return demangle(typeName.c_str());
}
};
int main(){
cout << typename_struct<int****>::name(); // Prints "int****"
return 0;
}
http://ideone.com/nLsFF0
Sources: https://stackoverflow.com/a/4541470/1938163
As for your question: those aren't constexpr
constructs, thus the evaluation happens at runtime although the templated parameters and code are instantiated at compile-time.
Using templates doesn't mean every instruction contained in there will be executed and resolved at "compile-time".
I believe you can't achieve this whole bunch of stuff at compile-time since there are de-mangling functions (ABI-specific) involved. If I interpreted your question wrong please let me know.
Alternative way without using recursive templates (but requires C++14):
#include <utility>
template<int...I> using is = std::integer_sequence<int,I...>;
template<int N> using make_is = std::make_integer_sequence<int,N>;
constexpr auto size(const char*s) { int i = 0; while(*s!=0){++i;++s;} return i; }
template<const char*, typename, const char*, typename>
struct concat_impl;
template<const char* S1, int... I1, const char* S2, int... I2>
struct concat_impl<S1, is<I1...>, S2, is<I2...>> {
static constexpr const char value[]
{
S1[I1]..., S2[I2]..., 0
};
};
template<const char* S1, const char* S2>
constexpr auto concat {
concat_impl<S1, make_is<size(S1)>, S2, make_is<size(S2)>>::value
};
Example:
constexpr const char a[] = "int";
constexpr const char c[] = "**";
#include <iostream>
int main()
{
std::cout << concat<a,b> << '\n';
}
append
characters to string can also be implemented like this, by replacing the second const char*
parameter with char...
.