Der Compiler versucht immer zu instanti aß jeden einzelnen Zweig von std :: conditional, auch diejenigen, die nicht genommen wurden. Um es anders auszudrücken, ist ein Kurzschluss nicht passiert.
std::conditional<B,T,F>
ist für den Zweck vorgesehen, um eine Auswahl zwischen compiletime gegebenen TypenT
und F
auszuführen, abhängig von den Booleschen B
. Die Wahl erfolgt durch Spezialisierung.Wenn B
wahr ist, die instanziiert Spezialisierung:
std::conditional<true,T,F>
{
typedef T type;
};
Und wenn B
falsch ist, die die instanziiert Spezialisierung:
std::conditional<false,T,F>
{
typedef F type;
};
Beachten Sie, dass entweder Spezialisierung, sowohl T
und F
muss instanziiert instanziiert werden. Es gibt keine "Verzweigungen". Der Begriff des "Kurzschließens" der Instanziierung von entweder std::conditional<true,T,F>
oder std::conditional<false,T,F>
könnte nur bedeuten nicht tun.
Also nein, ist es nicht möglich DeferInstantiation<U>
zu implementieren, für Typ-Parameter U
, so dass eine Instantiierung
std::conditional<{true|false},DeferInstantiation<T>,DeferInstantiation<F>>
nicht zur Folge hat Instanziierung DeferInstantiation<T>
und DeferInstantiation<F>>
, und deshalb von T
, und von F
.
Für eine compiletime Wahl der Ausführung als an dem oder zwei oder mehr Vorlagen instanziiert werden soll, stellt die Sprache Spezialisierung (wie gerade von std::conditional<B,T,F>
durch die Definition dargestellt selbst); es bietet Funktion Vorlage Überlast Auflösung, und es bietet SFINAE. Spezialisierung und Überladungsauflösung kann jeder synergetisch mit SFINAE genutzt werden, über die Bibliothek Unterstützung von std::enable_if<B,T>
Das Problem, das Sie in der Gestaltung der besonderen rekursiven Meta-Funktion , die Sie wollen behindert hat, ist nicht eine zwischen bestimmten der Wahl Typen, aber der Wahl der Vorlage , in die rekursive Instanziierung gerichtet werden soll. std::conditional
ist nicht zum Zweck. @ Pradhans Antwort zeigt, dass eine Vorlage, die sich von std::conditional
unterscheidet, gut geschrieben werden kann, um eine Compiletime-Auswahl zwischen zwei Vorlagen ohne zu bewirken, was zur Folge hat, dass beide instanziiert werden. Er wendet Spezialisierung an, um es zu tun.
Wie Sie bereits gesagt haben, haben Sie bereits eine Spezialisierungslösung für das Problem gefunden. Dies ist im Prinzip der richtige Weg, um die Template-Auswahl in rekursiven Meta-Funktionen rekursiv zu steuern. Mit dem Aufkommen von constexpr
, rekursive Meta-Funktionen nicht mehr als der Marktanteil von Probleme, die sie früher getan haben, und die meisten der Gehirnschmerzen, die sie verursacht ist eine Sache der Vergangenheit.
Das besondere Problem hier - bei compiletime zu bestimmen, ob eine Zeichenfolge ein Teil eines andere ist - ohne die Auseinandersetzung mit Vorlage Meta-Programmierung gelöst werden, und ohne compiletime Saiten anders als traditionellen Stringliterale darstellt:
#include <cstddef>
constexpr std::size_t str_len(char const *s)
{
return *s ? 1 + str_len(s + 1) : 0;
}
constexpr bool
is_substr(char const * src, char const *targ,
std::size_t si = 0, std::size_t ti = 0)
{
return !targ[ti] ? true :
str_len(src + si) < str_len(targ + ti) ? false :
src[si] == targ[ti] ?
is_substr(src,targ,si + 1, ti + 1) :
is_substr(src,targ,si + 1, 0);
}
// Compiletime tests...
static_assert(is_substr("",""),"");
static_assert(is_substr("qwerty",""),"");
static_assert(is_substr("qwerty","qwerty"),"");
static_assert(is_substr("qwerty","qwert"),"");
static_assert(is_substr("qwerty","werty"),"");
static_assert(is_substr("qwerty","wert"),"");
static_assert(is_substr("qwerty","er"),"");
static_assert(!is_substr("qwerty","qy"),"");
static_assert(!is_substr("qwerty","et"),"");
static_assert(!is_substr("qwerty","qwertyz"),"");
static_assert(!is_substr("qwerty","pqwerty"),"");
static_assert(!is_substr("","qwerty"),"");
int main()
{
return 0;
}
Dies wird als C++ 11 oder besser kompilieren.
Sie haben auch Gründe für den Wunsch compiletime Strings als CharList<char ...>
andere als wodurch sie zugänglich TMP compiletime Anfragen wie diese darzustellen. Wir können sehen, dass CharList<char ...Cs>
ein statisches Konstante size
Mitglied muss sizeof...(Cs)
Bewertung und hat eine statische at<N>()
Memberfunktion zum N
ten der ...Cs
auswertet. In diesem Fall (unter der Annahme, dass at<N>()
gedebuggt wird), könnte man anpassen is_substr
eine Template-Funktion zu erwarten CharList<char ...>
Parameter auf etwa den folgenden Zeilen:
#include <type_traits>
template<
class SrcList, class TargList, std::size_t SrcI = 0, std::size_t TargI = 0>
constexpr typename
std::enable_if<(TargI == TargList::size && SrcI <= SrcList::size),bool>::type
is_substr()
{
return true;
}
template<
class SrcList, class TargList, std::size_t SrcI = 0, std::size_t TargI = 0>
constexpr typename
std::enable_if<(TargI < TargList::size && SrcI == SrcList::size),bool>::type
is_substr()
{
return false;
}
template<
class SrcList, class TargList, std::size_t SrcI = 0, std::size_t TargI = 0>
constexpr typename
std::enable_if<(TargI < TargList::size && SrcI < SrcList::size),bool>::type
is_substr()
{
return SrcList::template at<SrcI>() == TargList::template at<TargI>() ?
is_substr<SrcList,TargList,SrcI + 1,TargI + 1>() :
is_substr<SrcList,TargList,SrcI + 1,0>();
}
, die die Anwendung von SFINAE zeigt, durch std::enable_if
Leveraged
Schließlich könnte man auch in diesem Programm interessiert sein:
#include <iostream>
template<char const * Arr>
struct string_lit_type
{
static constexpr const char * str = Arr;
static constexpr std::size_t size = str_len(str);
static constexpr char at(std::size_t i) {
return str[i];
}
};
constexpr char arr[] = "Hello World\n";
int main()
{
std::cout << string_lit_type<arr>::str;
std::cout << string_lit_type<arr>::size << std::endl;
std::cout << string_lit_type<arr>::at(0) << std::endl;
return 0;
}
, die Drucke:
Hello World
12
H
(Code mit g ++ kompiliert 4,9, klirren 3.5)