Generate unique string literal for asm from class template parameter - c++

I have a very special case, where I need to generate a unique assembler name for a variable declared in a class template. I need that name to be unique for every instance of the class template and I need to pass it to the asm keyword (see here).
My specific case looks somewhat like this:
template <size_t n>
struct StringLiteral
{
constexpr StringLiteral (const char (&str)[n])
{
std::copy_n (str, n, value);
}
char value[n];
static constexpr size_t len = n;
};
template <StringLiteral text>
class Foo
{
private:
template <size_t... i>
static const char* get (const std::index_sequence<i...>&)
{
__attribute__((section("<Some specific section>"), internal_linkage)) static const char t[text.len] asm ("<The unique label>") = { text.value[i]... };
return t;
}
public:
static const char* get()
{
return get (std::make_index_sequence<text.len>());
}
}
Where I'd like these three instances to contain three different replacements for "<The unique label>" in their get function:
auto* one = Foo<"Instance One">::get();
auto* two = Foo<"Instance Two">::get();
auto* three = Foo<"Instance Three">::get();
To my limited knowledge, it's only possible to pass hard coded string literals as assembler names to asm, but maybe someone knows some cool trickery. A name made up of a string prefix with a unique numerical postfix per template instance would be totally fine.
The compiler used is Apple Clang 14, so answers with compiler specific solutions are fine. The code uses C++ 20.

Related

Can static polymorphism (templates) be used despite type erasure?

Having returned relatively recently to C++ after decades of Java, I am currently struggling with a template-based approach to data conversion for instances where type erasure has been applied. Please bear with me, my nomenclature may still be off for C++-natives.
This is what I am trying to achieve:
Implement dynamic variables which are able to hold essentially any value type
Access the content of those variables using various other representations (string, ints, binary, ...)
Be able to hold variable instances in containers, independent of their value type
Convert between variable value and representation using conversion functions
Be able to introduce new representations just by providing new conversion functions
Constraints: use only C++-11 features if possible, no use of libraries like boost::any etc.
A rough sketch of this might look like this:
#include <iostream>
#include <vector>
void convert(const std::string &f, std::string &t) { t = f; }
void convert(const int &f, std::string &t) { t = std::to_string(f); }
void convert(const std::string &f, int &t) { t = std::stoi(f); }
void convert(const int &f, int &t) { t = f; }
struct Variable {
virtual void get(int &i) = 0;
virtual void get(std::string &s) = 0;
};
template <typename T> struct VariableImpl : Variable {
T value;
VariableImpl(const T &v) : value{v} {};
void get(int &i) { convert(value, i); };
void get(std::string &s) { convert(value, s); };
};
int main() {
VariableImpl<int> v1{42};
VariableImpl<std::string> v2{"1234"};
std::vector<Variable *> vars{&v1, &v2};
for (auto &v : vars) {
int i;
v->get(i);
std::string s;
v->get(s);
std::cout << "int representation: " << i <<
", string representation: " << s << std::endl;
}
return 0;
}
The code does what it is supposed to do, but obvoiusly I would like to get rid of Variable::get(int/std::string/...) and instead template them, because otherwise every new representation requires a definition and an implementation with the latter being exactly the same as all the others.
I've played with various approaches so far, like virtual templated, methods, applying the CRDT with intermediate type, various forms of wrappers, yet in all of them I get bitten by the erased value type of VariableImpl. On one hand, I think there might not be a solution, because after type erasure, the compiler cannot possibly know what templated getters and converter calls it must generate. On the other hand I think i might be missing something really essential here and there should be a solution despite the constraints mentioned above.
This is a classical double dispatch problem. The usual solution to this problem is to have some kind of dispatcher class with multiple implementations of the function you want to dispatch (get in your case). This is called the visitor pattern. The well-known drawback of it is the dependency cycle it creates (each class in the hierarchy depends on all other classes in the hierarchy). Thus there's a need to revisit it each time a new type is added. No amount of template wizardry eliminates it.
You don't have a specialised Visitor class, your Variable serves as a Visitor of itself, but this is a minor detail.
Since you don't like this solution, there is another one. It uses a registry of functions populated at run time and keyed on type identification of their arguments. This is sometimes called "Acyclic Visitor".
Here's a half-baked C++11-friendly implementation for your case.
#include <map>
#include <vector>
#include <typeinfo>
#include <typeindex>
#include <utility>
#include <functional>
#include <string>
#include <stdexcept>
struct Variable
{
virtual void convertValue(Variable& to) const = 0;
virtual ~Variable() {};
virtual std::type_index getTypeIdx() const = 0;
template <typename K> K get() const;
static std::map<std::pair<std::type_index, std::type_index>,
std::function<void(const Variable&, Variable&)>>
conversionMap;
template <typename T, typename K>
static void registerConversion(K (*fn)(const T&));
};
template <typename T>
struct VariableImpl : Variable
{
T value;
VariableImpl(const T &v) : value{v} {};
VariableImpl() : value{} {}; // this is needed for a declaration of
// `VariableImpl<K> below
// It can be avoided but it is
// a story for another day
void convertValue(Variable& to) const override
{
auto typeIdxFrom = getTypeIdx();
auto typeIdxTo = to.getTypeIdx();
if (typeIdxFrom == typeIdxTo) // no conversion needed
{
dynamic_cast<VariableImpl<T>&>(to).value = value;
}
else
{
auto fcnIter = conversionMap.find({getTypeIdx(), to.getTypeIdx()});
if (fcnIter != conversionMap.end())
{
fcnIter->second(*this, to);
}
else
throw std::logic_error("no conversion");
}
}
std::type_index getTypeIdx() const override
{
return std::type_index(typeid(T));
}
};
template <typename K> K Variable::get() const
{
VariableImpl<K> vk;
convertValue(vk);
return vk.value;
}
template <typename T, typename K>
void Variable::registerConversion(K (*fn)(const T&))
{
// add a mutex if you ever spread this over multiple threads
conversionMap[{std::type_index(typeid(T)), std::type_index(typeid(K))}] =
[fn](const Variable& from, Variable& to) {
dynamic_cast<VariableImpl<K>&>(to).value =
fn(dynamic_cast<const VariableImpl<T>&>(from).value);
};
}
Now of course you need to call registerConversion e.g. at the beginning of main and pass it each conversion function.
Variable::registerConversion(int_to_string);
Variable::registerConversion(string_to_int);
This is not ideal, but hardly anything is ever ideal.
Having said all that, I would recommend you revisit your design. Do you really need all these conversions? Why not pick one representation and stick with it?
Implement dynamic variables which are able to hold essentially any value type
Be able to hold variable instances in containers, independent of their value type
These two requirements are quite challenging on its own. The class templates don't really encourage inheritance, and you already did the right thing to hold what you asked for: introduced a common base class for the class template, which you can later refer to in order to store pointers of the said type in a collection.
Access the content of those variables using various other representations (string, ints, binary, ...)
Be able to introduce new representations just by providing new conversion functions
This is where it breaks. Function templates assume common implementation for different types, while inheritance assumes different implementation for the same types.
You goal is to introduce different implementation for different types, and in order to make your requirements viable you have to switch to one of those two options instead (or put up with a number of functions for each case which you have already introduced yourself)
Edit:
One of the strategies you may employ to enforce inheritance approach is generalisation of the arguments to the extent where they can be used interchangeably by the abstract interface. E.g. you may wrap the converting arguments inside of a union like this:
struct Variable {
struct converter_type {
enum { INT, STRING } type;
union {
int* m_int;
std::string* m_string;
};
};
virtual void get(converter_type& var) = 0;
virtual ~Variable() = default;
};
And then take whatever part of it inside of the implementation:
void get(converter_type& var) override {
switch (var.type) {
case converter_type::INT:
convert(value, var.m_int);
break;
case converter_type::STRING:
convert(value, var.m_string);
break;
}
}
To be honest I don't think this is a less verbose approach compared to just having a number of functions for each type combination, but i think you got the idea that you can just wrap your arguments somehow to cement the abstract class interface.
Implement std::any. It is similar to boost::any.
Create a conversion dispatcher based off typeids. Store your any alongside the conversion dispatcher.
"new conversion functions" have to be passed to the dispatcher.
When asked to convert to a type, pass that typeid to the dispatcher.
So we start with these 3 types:
using any = std::any; // implement this
using converter = std::function<any(any const&)>;
using convert_table = std::map<std::type_index, converter>;
using convert_lookup = convert_table(*)();
template<class T>
convert_table& lookup_convert_table() {
static convert_table t;
return t;
}
struct converter_any: any {
template<class T,
typename std::enable_if<
!std::is_same<typename std::decay<T>::type, converter_any>::value, bool
>::type = true
>
converter_any( T&& t ):
any(std::forward<T>(t)),
table(&lookup_convert_table<typename std::decay<T>::type>())
{}
converter_any(converter_any const&)=default;
converter_any(converter_any &&)=default;
converter_any& operator=(converter_any const&)=default;
converter_any& operator=(converter_any&&)=default;
~converter_any()=default;
converter_any()=default;
convert_table const* table = nullptr;
template<class U>
U convert_to() const {
if (!table)
throw 1; // make a better exception than int
auto it = table->find(typeid(U));
if (it == table->end())
throw 2; // make a better exception than int
any const& self = *this;
return any_cast<U>((it->second)(self));
}
};
template<class Dest, class Src>
bool add_converter_to_table( Dest(*f)(Src const&) ) {
lookup_convert_table<Src>()[typeid(Dest)] = [f](any const& s)->any {
Src src = std::any_cast<Src>(s);
auto r = f(src);
return r;
};
return true;
}
now your code looks like:
const bool bStringRegistered =
add_converter_to_table(+[](std::string const& f)->std::string{ return f; })
&& add_converter_to_table(+[](std::string const& f)->int{ return std::stoi(f); });
const bool bIntRegistered =
add_converter_to_table(+[](int const& i)->int{ return i; })
&& add_converter_to_table(+[](int const& i)->std::string{ return std::to_string(i); });
int main() {
converter_any v1{42};
converter_any v2{std::string("1234")};
std::vector<converter_any> vars{v1, v2}; // copies!
for (auto &v : vars) {
int i = v.convert_to<int>();
std::string s = v.convert_to<std::string>();
std::cout << "int representation: " << i <<
", string representation: " << s << std::endl;
}
}
live example.
...
Ok, what did I do?
I used any to be a smart void* that can store anything. Rewriting this is a bad idea, use someone else's implementation.
Then, I augmented it with a manually written virtual function table. Which table I add is determined by the constructor of my converter_any; here, I know the type stored, so I can store the right table.
Typically when using this technique, I'd know what functions are in there. For your implementation we do not; so the table is a map from the type id of the destination, to a conversion function.
The conversion function takes anys and returns anys -- again, don't repeat this work. And now it has a fixed signature.
To add support for a type, you independently register conversion functions. Here, my conversion function registration helper deduces the from type (to determine which table to register it in) and the destination type (to determine which entry in the table), and then automatically writes the any boxing/unboxing code for you.
...
At a higher level, what I'm doing is writing my own type erasure and object model. C++ has enough power that you can write your own object models, and when you want features that the default object model doesn't solve, well, roll a new object model.
Second, I'm using value types. A Java programmer isn't used to value types having polymorphic behavior, but much of C++ works much better if you write your code using value types.
So my converter_any is a polymorphic value type. You can store copies of them in vectors etc, and it just works.

constexpr string-literal checking: short syntax, no runtime possibility

EDIT: Renamed, as my final solution does not use a poisoning method.
I'm looking for a way to prevent a constexpr method from being called at runtime. I'm writing a function that accepts a string literal, so I cannot simply use a NTTP as a way to require a constexpr parameter:
template<const char* str>
auto func() {...}
Because then even legitimate constexpr uses become cumbersome, requiring values to have static linkage, and you can't feed in a string literal. I want to do:
constexpr auto func(const char* str) {...}
The reason is because I check the string against a list of values, and want to STATICALLY check that the parameter is contained in the allowed set. I can do this easily: by just throw()'ing in a constexpr function, you can cause a compile-time error. But I do not want the possibility of generating production code with some branch that causes the program to exit at runtime. That would cause a major problem in my field; this feature is a nice-to-have in a program that does "other important stuff" and bad things happen if the program terminates.
I read about a whole bunch of possible ways to do this:
Use C++20 consteval - don't have C++20
Use C++20 std::is_constant_evaluated - don't have C++20
Poison the method at runtime by returning a result to an undefined symbol (e.g. extern int i that never gets defined). The compiler never creates code which returns that symbol if the method is called at compile-time, but it does if the method is called at runtime, resulting in a link error. Works, but ugly linker error; not my favorite. A version of that is shown in my post here: Constexpr functions not called at compile-time if result is ignored.
In C++17, noexcept gets automatically added onto any call to a constexpr function that actually gets called in a constexpr context. So you can do noexcept(foo(1)) vs noexcept(foo(i)) for constexpr int foo(int i) (not explicitly declared noexcept) to detect whether i causes the call to be constexpr/not. But you can't do that from within a constexpr function that has accepted some parameter - you need to do it from the call-site. So: probably requires a helper MACRO (not my favorite but it works).
Create a lambda whose return type is invalid if certain variables outside the scope of the lambda are not constexpr. This post goes into detail: https://stackoverflow.com/a/40413051
So I'm leaning towards using #3 or #4 + a macro, but ***this post is about #5 ***, or totally new ideas.
Can anyone come up with a way to do #5 without a lambda, for example? After that, I want to see if I can come up with a way to use it within the constexpr function itself rather than requiring it to be used from the call-site. For now, just try to poison a constexpr function if it is called at runtime, forget about "detecting" whether the function call is constexpr.
I can re-create the results of #5 by creating a lambda in main as the author did, but that's not actually very useful, and I'm still not convinced that it's fully legal. To start with, anything that can be done with a lambda can be done without a lambda -- right??? I can't even get the original author's method to work without a lambda. That seems like a first required step to get it to work outside of main().
Below are a couple ideas I've tried to recreate #5 without a lambda. Live example with a billion more permutations, none of which work: https://onlinegdb.com/B1oRjpTGP
// Common
template<int>
using Void = void;
// Common
struct Delayer {
constexpr auto delayStatic(int input) { return input; }
};
// Attempt 1
template<typename PoisonDelayer>
constexpr auto procurePoison(int i) {
struct Poison {
// error: use of parameter from containing function
// constexpr auto operator()() const -> Void<(PoisonDelayer::delayStatic(i), 0)> {}
} poison;
return poison;
}
// Attempt 2
struct PoisonInnerTemplate {
const int& _i;
// Internal compiler error / use of this in a constexpr
template<typename PoisonDelayer>
auto drink() const -> Void<(PoisonDelayer::delayStatic(_i), 0)> {}
};
int main()
{
auto attempt1 = procurePoison<Delayer>(1);
constexpr int i = 1;
auto attempt2 = PoisonInnerTemplate{i};
attempt2.drink<Delayer>();
return 0;
}
One more thing: I toyed with the idea of making a pre-defined list of allowed tags (wrap the string in a struct so it can be a NTTP), and putting them in some kind of container, and then having a method to retrieve them. The problems are: (1) the call-site syntax gets quite verbose to use them, (2) although it'd be fine for the call-site to use a syntax like MyTags::TAG_ONE, my program needs to be able to know the full set of tags, so they need to be in an array or a template variable, (3) using an array doesn't work, because getting an array element produces an rvalue, which doesn't have linkage, so can't be fed as a NTTP, (4) using a template variable with explicit specialization to define each tag requires the template variable to be global-scope, which doesn't work well for me...
This is about the best I can do - I think it's kind of ugly...:
struct Tag {
const char* name;
};
template<auto& tag>
void foo() {}
struct Tags {
static constexpr Tag invalid = {};
static constexpr Tag tags[] = {{"abc"}, {"def"}};
template<size_t N>
static constexpr Tag tag = tags[N];
template<size_t N = 0>
static constexpr auto& getTag(const char* name) {
if constexpr(N<2) {
if(string_view(name)==tag<N>.name) {
return tag<N>;
} else {
return getTag<N+1>(name);
}
} else {
return invalid;
}
}
};
int main()
{
foo<Tags::getTag("abc")>();
}
Here's my own answer, which checks that a string literal is within an allowed set at COMPILE-TIME, then performs an action based upon the value of that string. No poisoning of constexpr functions is needed, and there are still no cumbersome requirements to provide string literals with static linkage.
Credit goes to Jarod42 for "shorthand option 2", which uses a gcc extension for string template user-defined literals, which is part of C++20 but not C++17.
I think I'm happy enough with any of the three "shorthand" call-site syntaxes. I would still welcome any alternatives or improvements, or pointers on what I messed up. Perfect forwarding, etc. is left as an exercise for the reader ;-)
Live demo: https://onlinegdb.com/S1K_7sb7D
// Helper for Shorthand Option 1 (below)
template<typename Singleton>
Singleton* singleton;
// Helper to store string literals at compile-time
template<typename ParentDispatcher>
struct Tag {
using Parent = ParentDispatcher;
const char* name;
};
// ---------------------------------
// DISPATCHER:
// ---------------------------------
// Call different functions at compile-time based upon
// a compile-time string literal.
// ---------------------------------
template<auto& nameArray, typename FuncTuple>
struct Dispatcher {
FuncTuple _funcs;
using DispatcherTag = Tag<Dispatcher>;
template<size_t nameIndex>
static constexpr DispatcherTag TAG = {nameArray[nameIndex]};
static constexpr DispatcherTag INVALID_TAG = {};
Dispatcher(const FuncTuple& funcs) : _funcs(funcs) {
singleton<Dispatcher> = this;
}
template<size_t nameIndex = 0>
static constexpr auto& tag(string_view name) {
if(name == nameArray[nameIndex]) {
return TAG<nameIndex>;
} else {
if constexpr (nameIndex+1 < nameArray.size()) {
return tag<nameIndex+1>(name);
} else {
return INVALID_TAG;
}
}
}
static constexpr size_t index(string_view name) {
for(size_t nameIndex = 0; nameIndex < nameArray.size(); ++nameIndex) {
if(name == nameArray[nameIndex]) {
return nameIndex;
}
}
return nameArray.size();
}
constexpr auto& operator()(const char* name) const {
return tag(name);
}
template<auto& tag, typename... Args>
auto call(Args... args) const {
static constexpr size_t INDEX = index(tag.name);
static constexpr bool VALID = INDEX != nameArray.size();
static_assert(VALID, "Invalid tag.");
return get<INDEX*VALID>(_funcs)(args...);
}
};
template<auto& nameArray, typename FuncTuple>
auto makeDispatcher(const FuncTuple& funcs) {
return Dispatcher<nameArray, FuncTuple>(funcs);
}
// ---------------------------------
// SHORTHAND: OPTION 1
// ---------------------------------
// Use a singleton pattern and a helper to let a tag be associated with a
// specific dispatcher, so that the call-site need not specify dispatcher twice
// ---------------------------------
template<auto& tag, typename... Args>
auto call(Args... args) {
using Tag = remove_reference_t<decltype(tag)>;
using ParentDispatcher = typename Tag::Parent;
static auto dispatcher = singleton<ParentDispatcher>;
return dispatcher->template call<tag>(args...);
}
// ---------------------------------
// SHORTHAND: OPTION 2
// ---------------------------------
// Use a string template user-defined literal operator to shorten call-site syntax
// gcc supports this as an extension implementing proposal N3599 (standardized in C++20)
// If warnings occur, try pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template"
// ---------------------------------
// Need characters to be in contiguous memory on the stack (not NTTPs) for TAG_FROM_LITERAL
template<char... name>
constexpr char NAME_FROM_LITERAL[] = {name..., '\0'};
// Don't need to specify Dispatcher with user-defined literal method; will use dispatcher.check<>()
struct TagFromLiteral {};
// Need to have a constexpr variable with linkage to use with dispatcher.check<>()
template<char... name>
constexpr Tag<TagFromLiteral> TAG_FROM_LITERAL = {NAME_FROM_LITERAL<name...>};
// Create a constexpr variable with linkage for use with dispatcher.check<>(), via "MyTag"_TAG
template<typename Char, Char... name>
constexpr auto& operator"" _TAG() {
return TAG_FROM_LITERAL<name...>;
}
// ---------------------------------
// SHORTHAND: OPTION 3
// ---------------------------------
// Use a macro so the call-site need not specify dispatcher twice
// ---------------------------------
#define DISPATCH(dispatcher, name) dispatcher.call<dispatcher(name)>
// ---------------------------------
// COMMON: TEST FUNCTIONS
// ---------------------------------
bool testFunc1(int) { cout << "testFunc1" << endl; }
bool testFunc2(float) { cout << "testFunc2" << endl; }
bool testFunc3(double) { cout << "testFunc3" << endl; }
static constexpr auto funcs = make_tuple(&testFunc1, &testFunc2, &testFunc3);
static constexpr auto names = array{"one", "two", "three"};
int main()
{
// Create a test dispatcher
auto dispatcher = makeDispatcher<names>(funcs);
// LONG-HAND: call syntax: a bit verbose, but operator() helps
dispatcher.call<dispatcher("one")>(1);
// SHORTHAND OPTION 1: non-member helper, singleton maps back to dispatcher
call<dispatcher("one")>(1);
// SHORTHAND OPTION 2: gcc extension for string UDL templates (C++20 standardizes this)
dispatcher.call<"one"_TAG>(1);
// SHORHAND OPTION 3: Macro
DISPATCH(dispatcher, "one")(1);
return 0;
}

How to pass an std::map with "any" enum to a function

I have many enum declarations like
typedef enum {
E_FOO_1,
E_FOO_RANDOM,
E_FOO_25,
} E_FOO;
typedef enum {
E_BAR_RANDOM,
E_BAR_SOMETHING,
E_BAR_WHATEVER,
} E_BAR;
and I need a mapping to strings
std::map<E_FOO, const char*> fooMap = {
{E_FOO_1, "completly different string"},
{E_FOO_RANDOM, "hi"},
{E_FOO_25, "down"},
};
std::map<E_BAR, const char*> barMap = {
{E_BAR_RANDOM, "1234"},
{E_BAR_SOMETHING, "3},
{E_BAR_WHATEVER, "45"},
};
Is there anyway to write a function which takes something like (uint8_t someEnumValue, std::map<any, const char*>) and simply returns the string?
In the real application the structure is much more complicated and the enums are handled by some C-code, which has no problem to handle the enum values as int or uint8_t but I am not very used to C++, so I see no way to pass these parameters to a general function.
Could it be done by using templates? And wouldn't that blow up the compiled code since for every enum the function needs to be compiled (the function would be in a bigger class, so I would need to template the whole class).
Thanks!
You can use a function template to accept any std::map whose value type is const char*:
template <typename Enum>
const char* get_string(std::uint8_t v, const std::map<Enum, const char*>& m)
{
return m.at(static_cast<Enum>(v));
}
live example on godbolt.org

How to correctly use variadic templates in C++11 with this simple example?

Using VS2013 (VC2012).
After reading many answers about variadic templates and failing with my own code, I want to ask about how to compile/achieve my example, which does not represent my whole need but in place I prefer to put in order to make it easier and cleaner for everyone to understand my point.
I preferably need a function which receives an arbitrary amount of (int, const char * tuples), and access any tuple from this list inside the function. Since I believe after reading over Internet this is not possible, I tried defining the variadic template with an arbitrary amount of a certain class which would contain the int and const char* members, and it fails.
Please note it's important I want to separate the declaration from the definition in different files:
phrases.h:
class CPhraseParamInfo { // Nothing, for easier example }
class CPhrases
{
template<class... T> void Test(T... paramsInfo);
}
phrases.cpp
template<CPhraseParamInfo...> void CPhrases::Test(CPhraseParamInfo... param)
{ // Nothing, for easier example }
Errors (translated):
error C2993: 'CPhraseParamInfo' : invalid type for the template parameter '__formal' without defined type
error C3543: 'CPhraseParamInfo': doesn't contain a parameter pack
error C2244: 'CPhrases::Test' : cannot match the function definition with an existent declaration
Remember I'd prefer the first method, if possible. I hope I was clear enough.
Thanks!
Thanks #Yakk. Here is expanded example with part of my real codework in order to show how to allow a last parameter to be used as arbritrary values passing (for certain phrase va_args processing), if anyone finds it useful. The key here is to call the variadic template function with the same amount of variadic class used on the template call list (< CPhraseParamInfo, ... >):
phrases.h:
class CPhrases:
{
template<class... ParamInfo, typename... Arg> static void
LoadForPlayer(CHL2RP_Player *player, char *dest, int maxlen, const char *header,
const char *prependText, ParamInfo&... paramsInfo, Arg... args)
{
CPhraseParamInfo paramsInfoBuff[] = { paramsInfo... };
LoadForPlayer(player, dest, maxlen, header, prependText, paramsInfoBuff, sizeof paramsInfoBuff, args...);
}
static void LoadForPlayer(CHL2RP_Player *player, char *dest, int maxlen, const char *header, const char *prependText,
CPhraseParamInfo *paramsInfoBuff, int paramCount, ...);
static FORCEINLINE void LoadRegionChat(CHL2RP_Player *player, char *dest, int maxlen, const char *talker, const char *message)
{
LoadForPlayer<CPhraseParamInfo, CPhraseParamInfo>(player, dest, maxlen, REGION_CHAT_HEADER, INDIAN_RED_CHAT_COLOR,
CPhraseParamInfo(CPhraseParamInfo::STRING, TEAM_CHAT_COLOR "%s" DEFAULT_CHAT_COLOR), CPhraseParamInfo(CPhraseParamInfo::STRING, "%s"), talker, message);
}
}
The definition of a template function must be visible at the point where it is used, barring unusual cases.
You could do this:
class CPhraseParamInfo { // Nothing, for easier example }
class CPhrases {
void Test( CPhraseParamInfo* start, CPhraseParamInfo* end );
template<class... T> void Test(T... paramsInfo) {
CPhraseParamInfo buff[]={paramsInfo...};
return Test(buff, buff+sizeof...(paramsInfo));
}
};
then in your cpp file:
void CPhrases::Test(CPhraseParamInfo* start, CPhraseParamInfo* end)
{
// Nothing, for easier example
}
or something similar.

Is it possible to get a char* name from a template type in C++

I want to get the string name (const char*) of a template type. Unfortunately I don't have access to RTTI.
template< typename T >
struct SomeClass
{
const char* GetClassName() const { return /* magic goes here */; }
}
So
SomeClass<int> sc;
sc.GetClassName(); // returns "int"
Is this possible? I can't find a way and am about to give up. Thanks for the help.
No and it will not work reliable with typeid either. It will give you some internal string that depends on the compiler implementation. Something like "int", but also "i" is common for int.
By the way, if what you want is to only compare whether two types are the same, you don't need to convert them to a string first. You can just do
template<typename A, typename B>
struct is_same { enum { value = false }; };
template<typename A>
struct is_same<A, A> { enum { value = true }; };
And then do
if(is_same<T, U>::value) { ... }
Boost already has such a template, and the next C++ Standard will have std::is_same too.
Manual registration of types
You can specialize on the types like this:
template<typename>
struct to_string {
// optionally, add other information, like the size
// of the string.
static char const* value() { return "unknown"; }
};
#define DEF_TYPE(X) \
template<> struct to_string<X> { \
static char const* value() { return #X; } \
}
DEF_TYPE(int); DEF_TYPE(bool); DEF_TYPE(char); ...
So, you can use it like
char const *s = to_string<T>::value();
Of course, you can also get rid of the primary template definition (and keep only the forward declaration) if you want to get a compile time error if the type is not known. I just included it here for completion.
I used static data-members of char const* previously, but they cause some intricate problems, like questions where to put declarations of them, and so on. Class specializations like above solve the issue easily.
Automatic, depending on GCC
Another approach is to rely on compiler internals. In GCC, the following gives me reasonable results:
template<typename T>
std::string print_T() {
return __PRETTY_FUNCTION__;
}
Returning for std::string.
std::string print_T() [with T = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]
Some substr magic intermixed with find will give you the string representation you look for.
The really easy solution: Just pass a string object to the constructor of SomeClass that says what the type is.
Example:
#define TO_STRING(type) #type
SomeClass<int> s(TO_STRING(int));
Simply store it and display it in the implementation of GetClassName.
Slightly more complicated solution, but still pretty easy:
#define DEC_SOMECLASS(T, name) SomeClass<T> name; name.sType = #T;
template< typename T >
struct SomeClass
{
const char* GetClassName() const { return sType.c_str(); }
std::string sType;
};
int main(int argc, char **argv)
{
DEC_SOMECLASS(int, s);
const char *p = s.GetClassName();
return 0;
}
Template non type solution:
You could also make your own type ids and have a function to convert to and from the ID and the string representation.
Then you can pass the ID when you declare the type as a template non-type parameter:
template< typename T, int TYPEID>
struct SomeClass
{
const char* GetClassName() const { return GetTypeIDString(TYPEID); }
};
...
SomeClass<std::string, STRING_ID> s1;
SomeClass<int, INT_ID> s2;
You can try something like this (warning this is just off the top of my head, so there may be compile errors, etc..)
template <typename T>
const char* GetTypeName()
{
STATIC_ASSERT(0); // Not implemented for this type
}
#define STR(x) #x
#define GETTYPENAME(x) str(x) template <> const char* GetTypeName<x>() { return STR(x); }
// Add more as needed
GETTYPENAME(int)
GETTYPENAME(char)
GETTYPENAME(someclass)
template< typename T >
struct SomeClass
{
const char* GetClassName() const { return GetTypeName<T>; }
}
This will work for any type that you add a GETTYPENAME(type) line for. It has the advantage that it works without modifying the types you are interested in, and will work with built-in and pointer types. It does have the distinct disadvantage that you must a line for every type you want to use.
Without using the built-in RTTI, you're going to have to add the information yourself somewhere, either Brian R. Bondy's answer or dirkgently's will work. Along with my answer, you have three different locations to add that information:
At object creation time using SomeClass<int>("int")
In the class using dirkgently's compile-time RTTI or virtual functions
With the template using my solution.
All three will work, it's just a matter of where you'll end up with the least maintenance headaches in your situation.
By you don't have access to RTTI, does that mean you can't use typeid(T).name()? Because that's pretty much the only way to do it with the compiler's help.
Is it very important for the types to have unique names, or are the names going to be persisted somehow? If so, you should consider giving them something more robust than just the name of the class as declared in the code. You can give two classes the same unqualified name by putting them in different namespaces. You can also put two classes with the same name (including namespace qualification) in two different DLLs on Windows, so you need the identify of the DLL to be included in the name as well.
It all depends on what you're going to do with the strings, of course.
You can add a little magic yourself. Something like:
#include <iostream>
#define str(x) #x
#define xstr(x) str(x)
#define make_pre(C) concat(C, <)
#define make_post(t) concat(t, >)
#define make_type(C, T) make_pre(C) ## make_post(T)
#define CTTI_REFLECTION(T, x) static std::string my_typeid() \
{ return xstr(make_type(T, x)); }
// the dark magic of Compile Time Type Information (TM)
#define CTTI_REFLECTION(x) static const char * my_typeid() \
{ return xstr(make_type(T, x)); }
#define CREATE_TEMPLATE(class_name, type) template<> \
struct class_name <type>{ \
CTTI_REFLECTION(class_name, type) \
};
// dummy, we'll specialize from this later
template<typename T> struct test_reflection;
// create an actual class
CREATE_TEMPLATE(test_reflection, int)
struct test_reflection {
CTTI_REFLECTION(test_reflection)
};
int main(int argc, char* argv[])
{
std::cout << test_reflection<int>::my_typeid();
}
I'll make the inspector a static function (and hence non-const).
No, sorry.
And RTTI won't even compile if you try to use it on int.