
Steven Lu
Aktuell habe ich:
template <typename T> struct typename_struct<T*> {
static char const* name() {
return (std::string(typename_struct<T>::name()) + "*").c_str();
}
};
Ich frage mich, ob ich das ganze Bit vermeiden kann, wo ich gezwungen bin, eine Zeichenfolge zuzuweisen, um die Verkettung durchzuführen.
Dies geschieht alles zur Kompilierzeit, dh ich beabsichtige, die Zeichenfolge zu erhalten "int****"
wenn ich referenziere typename_struct<int****>::name()
. (Gehen Sie davon aus, dass ich eine entsprechende Spezialisierung für deklariert habe int
die zurückkehrt "int"
)
Wenn der Code jetzt geschrieben ist, führt der Compiler die Verkettung mit std::string nur während der Kompilierzeit durch? (Ich wäre damit einverstanden) Oder führt ein solcher Aufruf zur Laufzeit zu 4 std::string-basierten Verkettungen? (damit wäre ich nicht einverstanden)

pw
So etwas könntest du gebrauchen. Alles geschieht zur Kompilierzeit. Spezialisieren Sie base_typename_struct, um Ihre primitiven Typen zu definieren.
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;
}

Hedede
Alternativer Weg ohne rekursive Templates (erfordert aber 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
};
Beispiel:
constexpr const char a[] = "int";
constexpr const char c[] = "**";
#include <iostream>
int main()
{
std::cout << concat<a,b> << '\n';
}
append
Zeichen in Zeichenfolge können auch so implementiert werden, indem das zweite ersetzt wird const char*
Parameter mit char...
.

Marco A.
Ich bin mir nicht sicher, wonach Sie suchen, aber ich glaube, Sie interessieren sich für eine Kombination aus Typ-ID und Namensentwirrung (welchen Compiler verwenden Sie?)
In gcc wäre es so etwas wie
#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
Quellen: https://stackoverflow.com/a/4541470/1938163
Zu deiner Frage: Das sind sie nicht constexpr
Konstrukte, daher erfolgt die Auswertung zur Laufzeit, obwohl die Vorlagenparameter und der Code zur Kompilierzeit instanziiert werden.
Die Verwendung von Vorlagen bedeutet nicht, dass jede darin enthaltene Anweisung zur “Kompilierzeit” ausgeführt und aufgelöst wird.
Ich glaube, Sie können diese ganze Menge Zeug nicht zur Kompilierzeit erreichen, da De-Mangling-Funktionen (ABI-spezifisch) beteiligt sind. Wenn ich Ihre Frage falsch interpretiert habe, lassen Sie es mich bitte wissen.
#include <iostream>
//
***************************************************************************
template<const char* S1, const char* S2, size_t I1 = 0, size_t I2 = 0, char = S1[I1], char = S2[I2], char... Chars>
struct Concat : Concat<S1, S2, I1 + 1, I2, S1[I1 + 1], S2[I2], Chars..., S1[I1]>
{
};
// ****************************************************************************
template<const char* S1, const char* S2, size_t I1, size_t I2, char C2, char... Chars>
struct Concat<S1, S2, I1, I2, 0, C2, Chars...> : Concat<S1, S2, I1, I2 + 1, 0, S2[I2 + 1], Chars..., S2[I2]>
{
};
// ****************************************************************************
template<const char* S1, const char* S2, size_t N1, size_t N2, char... Chars>
struct Concat<S1, S2, N1, N2, 0, 0, Chars...>
{
static constexpr const char Text[] = { Chars... , 0 };
};
// ****************************************************************************
static constexpr const char A[] = "123";
static constexpr const char B[] = "456";
// ****************************************************************************
int main(int argc, char* argv[]){
std::cout << Concat<A, B>::Text << std::endl;
return 0;
}
10188100cookie-checkKompilierzeitzeichenfolgen in einer Vorlage zur Kompilierzeit verketten?yes
Noch besser wäre es, das Bit zu vermeiden, in dem Sie einen ungültigen Zeiger (auf freigegebenen Speicher) zurückgeben.
– Mike Seymour
16. Juli 2014 um 14:32 Uhr
@MikeSeymour Guter Punkt. Es scheint, als würde man den Rückgabetyp auf setzen
char const*
ist einfach nicht praktikabel– Steven Lu
16. Juli 2014 um 14:46 Uhr
std::string
verwendet dynamischen Speicher, daher kann ich mir keinen Grund vorstellen, dies beim Kompilierungstyp zu tun, insbesondere nicht für die Leistung.– Neil Kirk
16. Juli 2014 um 16:50 Uhr
@NeilKirk der Punkt ist, dass ich es nicht verwenden muss
std::string
– Steven Lu
16. Juli 2014 um 17:39 Uhr
Einen echten C++-String-Typ zur Kompilierzeit zu haben, wäre ein großartiges Werkzeug, das man im Standard haben könnte, und es ist machbar, aber es ist noch nicht passiert. Diese neue Vorschlag ist aber interessant.
– hellseherisch
16. Juli 2014 um 22:09 Uhr