Sök…
Anmärkningar
Typegenskaper är mallkonstruktioner som används för att jämföra och testa egenskaperna hos olika typer vid sammanställningstiden. De kan användas för att tillhandahålla villkorad logik vid sammanställningstid som kan begränsa eller utöka funktionaliteten för din kod på ett specifikt sätt. Typdragsbiblioteket fördes in med c++11
standarden som ger ett antal olika funktioner. Det är också möjligt att skapa dina egna typegenskaper.
Standardtyp
type_traits
rubriken innehåller en uppsättning mallklasser och hjälpare för att transformera och kontrollera egenskaperna hos typer vid kompileringstid.
Dessa egenskaper används vanligtvis i mallar för att kontrollera om användarfel, stödjer generisk programmering och möjliggör optimeringar.
De flesta typdrag används för att kontrollera om en typ uppfyller vissa kriterier. Dessa har följande form:
template <class T> struct is_foo;
Om mallklassen är instanserad med en typ som uppfyller vissa kriterier foo
, is_foo<T>
från std::integral_constant<bool,true>
(aka std::true_type
), annars ärver den från std::integral_constant<bool,false>
(aka std::false_type
). Detta ger egenskaperna följande medlemmar:
Konstanter anter~~POS=HEADCOMP
static constexpr bool value
true
om T
uppfyller kriterierna foo
, false
annars
funktioner
operator bool
Returnerar value
bool operator()
Returnerar value
typer
namn | Definition |
---|---|
value_type | bool |
type | std::integral_constant<bool,value> |
Egenskapen kan sedan användas i konstruktioner som static_assert
eller std::enable_if
. Ett exempel med std::is_pointer
:
template <typename T>
void i_require_a_pointer (T t) {
static_assert(std::is_pointer<T>::value, "T must be a pointer type");
}
//Overload for when T is not a pointer type
template <typename T>
typename std::enable_if<!std::is_pointer<T>::value>::type
does_something_special_with_pointer (T t) {
//Do something boring
}
//Overload for when T is a pointer type
template <typename T>
typename std::enable_if<std::is_pointer<T>::value>::type
does_something_special_with_pointer (T t) {
//Do something special
}
Det finns också olika drag som omvandlar typer, såsom std::add_pointer
och std::underlying_type
. Dessa egenskaper exponera allmänhet en enda type
medlem typ som innehåller den transformerade typen. Exempelvis är std::add_pointer<int>::type
int*
.
Skriv relationer med std :: is_same
std::is_same<T, T>
används för att jämföra två typer. Det kommer att utvärderas som booleskt, sant om typerna är desamma och falska om annat.
t.ex
// Prints true on most x86 and x86_64 compilers.
std::cout << std::is_same<int, int32_t>::value << "\n";
// Prints false on all compilers.
std::cout << std::is_same<float, int>::value << "\n";
// Prints false on all compilers.
std::cout << std::is_same<unsigned int, int>::value << "\n";
std::is_same
typ fungerar också oavsett typdefs. Detta visas faktiskt i det första exemplet när man jämför int == int32_t
men detta är inte helt klart.
t.ex
// Prints true on all compilers.
typedef int MyType
std::cout << std::is_same<int, MyType>::value << "\n";
Använd std::is_same
att varna när du använder en mall eller funktion på ett felaktigt sätt.
När det kombineras med en statisk std::is_same
kan std::is_same
mallen vara ett värdefullt verktyg för att upprätthålla korrekt användning av mallade klasser och funktioner.
t.ex. en funktion som endast tillåter inmatning från ett int
och ett val av två strukturer.
#include <type_traits>
struct foo {
int member;
// Other variables
};
struct bar {
char member;
};
template<typename T>
int AddStructMember(T var1, int var2) {
// If type T != foo || T != bar then show error message.
static_assert(std::is_same<T, foo>::value ||
std::is_same<T, bar>::value,
"This function does not support the specified type.");
return var1.member + var2;
}
Grundläggande typdrag
Det finns ett antal olika typdrag som jämför mer generella typer.
Är integrerad:
Utvärderar som sant för alla heltalstyper int
, char
, long
, unsigned int
etc.
std::cout << std::is_integral<int>::value << "\n"; // Prints true.
std::cout << std::is_integral<char>::value << "\n"; // Prints true.
std::cout << std::is_integral<float>::value << "\n"; // Prints false.
Är flytande punkt:
Utvärderar som sant för alla typer av flytande punkter. float
, double
, long double
etc.
std::cout << std::is_floating_point<float>::value << "\n"; // Prints true.
std::cout << std::is_floating_point<double>::value << "\n"; // Prints true.
std::cout << std::is_floating_point<char>::value << "\n"; // Prints false.
Är Enum:
Utvärderar som sant för alla uppräknade typer, inklusive enum class
.
enum fruit {apple, pair, banana};
enum class vegetable {carrot, spinach, leek};
std::cout << std::is_enum<fruit>::value << "\n"; // Prints true.
std::cout << std::is_enum<vegetable>::value << "\n"; // Prints true.
std::cout << std::is_enum<int>::value << "\n"; // Prints false.
Är pekaren:
Utvärderar som sant för alla pekare.
std::cout << std::is_pointer<int *>::value << "\n"; // Prints true.
typedef int* MyPTR;
std::cout << std::is_pointer<MyPTR>::value << "\n"; // Prints true.
std::cout << std::is_pointer<int>::value << "\n"; // Prints false.
Är klass:
Utvärderar som sant för alla klasser och strukturer, med undantag för enum class
.
struct FOO {int x, y;};
class BAR {
public:
int x, y;
};
enum class fruit {apple, pair, banana};
std::cout << std::is_class<FOO>::value << "\n"; // Prints true.
std::cout << std::is_class<BAR>::value << "\n"; // Prints true.
std::cout << std::is_class<fruit>::value << "\n"; // Prints false.
std::cout << std::is_class<int>::value << "\n"; // Prints false.
Skriv egenskaper
Typegenskaper jämför modifierarna som kan placeras på olika variabler. Användbarheten av dessa typdrag är inte alltid uppenbar.
Obs: Exemplet nedan skulle bara ge en förbättring av en icke-optimerande kompilator. Det är ett enkelt bevis på koncept, snarare än komplexa exempel.
t.ex. snabb dela med fyra.
template<typename T>
inline T FastDivideByFour(cont T &var) {
// Will give an error if the inputted type is not an unsigned integral type.
static_assert(std::is_unsigned<T>::value && std::is_integral<T>::value,
"This function is only designed for unsigned integral types.");
return (var >> 2);
}
Är konstant:
Detta kommer att utvärderas som sant när typen är konstant.
std::cout << std::is_const<const int>::value << "\n"; // Prints true.
std::cout << std::is_const<int>::value << "\n"; // Prints false.
Är flyktig:
Detta kommer att utvärderas som sant när typen är flyktig.
std::cout << std::is_volatile<static volatile int>::value << "\n"; // Prints true.
std::cout << std::is_const<const int>::value << "\n"; // Prints false.
Är undertecknad:
Detta kommer att utvärderas som sant för alla signerade typer.
std::cout << std::is_signed<int>::value << "\n"; // Prints true.
std::cout << std::is_signed<float>::value << "\n"; // Prints true.
std::cout << std::is_signed<unsigned int>::value << "\n"; // Prints false.
std::cout << std::is_signed<uint8_t>::value << "\n"; // Prints false.
Är inte undertecknad:
Utvärderar som sant för alla icke signerade typer.
std::cout << std::is_unsigned<unsigned int>::value << "\n"; // Prints true.
std::cout << std::is_signed<uint8_t>::value << "\n"; // Prints true.
std::cout << std::is_unsigned<int>::value << "\n"; // Prints false.
std::cout << std::is_signed<float>::value << "\n"; // Prints false.