How to determine arg type in c++ - c++

in gcc, I can use following code:
#define is_t(smth, type) ({int is_t_result; if (__builtin_types_compatible_p(__typeof__(smth), type)) {is_t_result = 1;}; is_t_result;})
but when I run it in googletest(c++), it raise
error: expected primary-expression before ‘__typeof__’
is there alternative to implement is_t in cpp?

This is a very complicated question, because there are many different ways to "detect types", depending on what it is you are trying to accomplish. There are basically two different categories of "type checking": compile-time and run-time. In terms of compile-time checking, it is very common to use "duck-typing" with C++ templates (it works if it satisfies the implicit requirements); however, there are some cases where this is not sufficient, and <type_traits> and static_assert provide ways to enforce requirements more explicitly, while decltype allows one to refer to the type that would be returned by an expression. Type conversion at runtime is less common in C++ (usually it is done implicitly through "dynamic dispatch", a.k.a. virtual functions); however, in terms of explicitly checking the runtime type of an object, there is the dynamic_cast<T> mechanism.
Long-story short, though, your is_t() macro is probably best replaced by the builtin mechanisms for type-detection in C++. If you are using older versions of C++, Boost provides widely compatible equivalents that work across many C++ compilers and both C++98 and C++11. Doing so will make it much clearer what you mean by the variable being of that type. (E.g. is it declared to be exactly of that type, does it have that runtime type, is it declared to be of a type that is assignable to the other type).

Related

Why do I need to include <compare> header to get <=> to compile?

I know the technical answer is: because the standard says so.
But I am confused regarding the motivation:
I see nothing "library" in the defaulting the <=>: it may return some type that is technically defined in std but it is a "fake library" type in a sense that compiler must know about it since it must be able to default operator <=> with auto return type (not to mention that error messages in good compilers specify <compare> so it is clear that there is a language<=>library link here).
So I understand there is some library functionality that might require me to include <compare> but I do not understand why defaulting <=> requires me to include that header since compiler anyway has to know about everything needed to make the <=>.
Note: I know most of the time some other standard headers will include the <compare>, this is a question about language/library design, not that much about one extra line that C++ forces me to write without a good reason.
it may return some type that is technically defined in std but it is a "fake library" type in a sense
Well, <=> returns types that are very much real, that are actually defined in <compare> and implemented there. In the same way that an initializer list is used to construct a std::initializer_list<T>, which is very much a real type that is actually defined in <initializer_list>. And typeinfo in <typeinfo>.
And those comparison types - std::strong_ordering, std::weak_ordering, and std::partial_ordering (and originally also std::strong_equality and std::weak_equality) - themselves have non-trivial conversion semantics and other operations defined on them, that we may want to change in the future. They'd be very special language types indeed, where the convertibility only goes in one direction but in a way that's very much unlike inheritance (there are only three values for the total ordering types, but four for the partial one...). It's really much easier to define these as real library types and then specify their interaction as real library code.
that compiler must know about it since it must be able to default operator<=> with auto return type
Kind of, but not really. The compiler knows what the names of the types are, and how to produce values of them for the fundamental types, but it doesn't actually need to know anything more than that. The rule for the return type is basically hardcoded based on the types that the underyling members' <=>s return, don't need to know what those actual types look like to do that. And then you're just invoking functions that do... whatever.
The cost of you having to include a header is typing #include <compare> and then parse it. The cost of the compiler having to synthesize these types is a cost that would have to be paid for every TU, whether or not it does any three-way comparisons. Plus if/when we want to change these types, it's easier to change library types than language types anyway.

What are the similarities and differences between C++'s concepts and Rust's traits?

In Rust, the main tool for abstraction are traits. In C++, there are two tools for abstractions: abstract classes and templates. To get rid of some of the disadvantages of using templates (e.g. hard to read error messages), C++ introduced concepts which are "named sets of requirements".
Both features seem to be fairly similar:
Defining a trait/concept is done by listing requirements.
Both can be used to bound/restrict generic/template type parameters.
Rust traits and C++ templates with concepts are both monomorphized (I know Rust traits can also be used with dynamic dispatch, but that's a different story).
But from what I understand, there are also notable differences. For example, C++'s concepts seem to define a set of expressions that have to be valid instead of listing function signatures. But there is a lot of different and confusing information out there (maybe because concepts only land in C++20?). That's why I'd like to know: what exactly are the differences between and the similarities of C++'s concepts and Rust's traits?
Are there features that are only offered by either concepts or traits? E.g. what about Rust's associated types and consts? Or bounding a type by multiple traits/concepts?
Disclaimer: I have not yet used concepts, all I know about them was gleaned from the various proposals and cppreference, so take this answer with a grain of salt.
Run-Time Polymorphism
Rust Traits are used both for Compile-Time Polymorphism and, sometimes, Run-Time Polymorphism; Concepts are only about Compile-Time Polymorphism.
Structural vs Nominal.
The greatest difference between Concepts and Traits is that Concepts use structural typing whereas Traits use nominal typing:
In C++ a type never explicitly satisfies a Concept; it may "accidentally" satisfy it if it happens to satisfy all requirements.
In Rust a specific syntactic construct impl Trait for Type is used to explicitly indicates that a type implements a Trait.
There are a number of consequences; in general Nominal Typing is better from a maintainability point of view -- adding a requirement to a Trait -- whereas Structural Typing is better a bridging 3rd party libraries -- a type from library A can satisfy a Concept from library B without them being aware of each other.
Constraints
Traits are mandatory:
No method can be called on a variable of a generic type without this type being required to implement a trait providing the method.
Concepts are entirely optional:
A method can be called on a variable of a generic type without this type being required to satisfy any Concept, or being constrained in any way.
A method can be called on a variable of a generic type satisfying a Concept (or several) without that method being specified by any Concept or Constraint.
Constraints (see note) can be entirely ad-hoc, and specify requirements without using a named Concept; and once again, they are entirely optional.
Note: a Constraint is introduced by a requires clause and specifies either ad-hoc requirements or requirements based on Concepts.
Requirements
The set of expressible requirements is different:
Concepts/Constraints work by substitution, so allow the whole breadth of the languages; requirements include: nested types/constants/variables, methods, fields, ability to be used as an argument of another function/method, ability to used as a generic argument of another type, and combinations thereof.
Traits, by contrast, only allow a small set of requirements: associated types/constants, and methods.
Overload Selection
Rust has no concept of ad-hoc overloading, overloading only occurs by Traits and specialization is not possible yet.
C++ Constraints can be used to "order" overloads from least specific to most specific, so the compiler can automatically select the most specific overload for which requirements are satisfied.
Note: prior to this, either SFINAE or tag-dispatching would be used in C++ to achieve the selection; calisthenics were required to work with open-ended overload sets.
Disjunction
How to use this feature is not quite clear to me yet.
The requirement mechanisms in Rust are purely additive (conjunctions, aka &&), in contrast, in C++ requires clauses can contain disjunctions (aka ||).

C++: are "trait" and "meta-function" synonymous?

Or, does trait perhaps refer to a specific way to utilizing meta-functions?
If they are not synonymous, please point me to some examples of traits which are not meta-functions or those of meta-functions which are not traits. An actually working piece of code, perhaps within STL or Boost libraries, would be appreciated rather than a contrived toy example.
I'd like to see how experts in this field of C++ programming use these terminologies. I'm not sure if there are authoritative definitions of them...
Thanks in advance!
Clarification: It's not that I looking for any examples of traits or meta-functions. I've been using tens (if not hundreds) of them at my day job.
"Venn0110". Licensed under Public Domain via Commons.
"Meta" is C++ terminology for template programming. A clear example is the Boost Meta Programming Library (MPL).
In this sense, a meta-function is a function whose domain is not objects but C++ constructs. The common inputs are therefore types, ordinary functions and other templates.
A simple meta-function is for example template<typename T> using Foo = Bar<T, int> which has as its input a type T and as its output a type Foo<T>. Trivial, yes, but ordinary functions can be trivial too.
A trait is a metafunction whose codomain is a constant expression, often boolean. E.g. is_foo<T>::value obviously is boolean. The oldest trait in this sense is sizeof(T) whose codomain is size_t.
The terms are not equivalent.
Meta functions
The term is not defined in the C++ Standard.
There seem to be two main contending definitions:
1) "meta-functions derive/calculate/map-to values or types (based on their arguments/parameters) at compile time", and/or
constexpr functions may or may not be included in any given person's definition/conception; there's functional overlap, but much existing writing mentioning meta functions predates or just doesn't also discuss constexpr functions, so it's hard to know whether any definition or examples given deliberately leaves room for or excludes them
2) "meta-functions are functions and/or classes utilising template meta-programming", which specifically means a core of code (the template) may be reused for different parameters, performing some code generation or transformation based thereon
it's not necessarily the case that a meta-programming's final product is a compile-time type or constant - it may be a function intended for use with runtime values or data
A small survey of top google results for "meta function c++"
"metafunctions accept types and compile-time constants as parameters and return types/constants. A metafunction, contrary to its name, is a class template."
"code...executed and its result used while...compiling. ...meta-functions can compute two things: values or types"
this article uses "meta function" to refer to class templates yielding compile-time values/types
Traits
The C++ Standard doesn't define "traits", but does define "traits class"es:
17.3.25 [defns.traits] traits class
a class that encapsulates a set of types and functions necessary for class templates and function templates to manipulate objects of types for which they are instantiated
[ Note: Traits classes defined in Clauses 21, 22 and 27 are character traits, which provide the character handling support needed by the string and iostream classes. —end note ]
I'd add that traits can have values, as well as types and functions - for example rank exposes ::value. Traits provide types/values offering insight into either the parameter type itself, or the behaviour desired of the system using the trait when that system's working on variables of that type.
The Standard Library's character traits contain example of runtime functionality: for example X::length(p), X::find(p, n, c).
The <type_traits> header in the C++ Standard Library is a good place to get an initial feel for what kind of things traits can be used for.
Traits are traditionally and typically (but now C++11 provides constexpr functions not necessarily) classes, as distinct from functions meta- or otherwise.
A trait might tell you if a parameter T is constant or not, whether it's serialisable, or whether it should be compressed when transmitted via TCP: whatever some other general-purpose code might need to customise its behaviour for the range of types it handles.
Sometimes traits will be provided by the system that uses them - other times they can be supplied by client code wishing to customise its behaviour on a per-type basis.
Traits may deduce things using various tests of the parameter types, or they may be hand-crafted specialisations hard-coding values for specific types.
This ACCU introduction to traits](http://accu.org/index.php/journals/442) is worth reading, and includes this quote from the creator of C++:
Think of a trait as a small object whose main purpose is to carry information used by another object or algorithm to determine "policy" or "implementation details". - Bjarne Stroustrup
Contrasting "meta function" with "traits"
Regardless of which definition of meta function you adopt, the criteria relates to implementation details: when the function can be evaluated, and/or whether it involves code generation/transformation. That contrasts with traits, where the key concept/requirement is the purpose to which they're put, not the common - but far from universal - implementation using template specialisations or instantiations, or any capacity for compile time vs run-time evaluation.
A metafunction (in the context of C++) is a function that produces a result that can be used at compile time. The result can either be types (which can only be obtained at compile time by definition, using techniques such as partial specialisation) or values (which can be computed at compile time, using the fact that template parameters can be integral values, not just types).
A trait is essentially a class (or object) that packages up information (policy contraints, type characteristics, implementation details) for use by another class (or object) at compile time. The information packaged up can consist of type information (e.g. typedefs) or properties of interest. For example, std::numeric_limits<T> (available through <limits>) is a "type trait" which provides information about arithmetic types (e.g. is T an integral type? is the set of values a T can represent bounded or finite? is T signed? etc). The information is packaged in a form so that metaprograms (i.e. template functions or classes) can use the information at compile time. For example, a template metafunction might use information from a type trait to ensure the template is only instantiated for unsigned integral types, and trigger a compilation error if an attempt is made to instantiate the template for other types.
In this sense, a trait is a type of metafunction that provides information at compile time for use by other metafunctions.
As far as I know, there aren't any formal definitions of these terms. So I'll provide the ones that I use.
Metafunctions are templates which return a type. Usually, the returned result is a type which contains a member type named "type" so it can be accessed via the suffix ::type. Example invoking a metafunction:
using new_type = std::common_type<int, char>::type;
(see http://en.cppreference.com/w/cpp/types/common_type)
A trait would be be special type of metafunction which returns a result convertible to bool. Example:
bool ic = std::is_convertible<char, int>::type;
Note that nowadays, the requirement that a metafunction result have a member name "type" is relaxed so some metafunctions might be defined in such a manner that the ::type can be dropped. Example:
bool ic = std::experimental::is_convertible_v<char, int>;

How are C++ casts implemented?

The C++ casts static_cast, const_cast, reinterpret_cast have a template-like syntax, e.g.
long foo = 3;
int bar = static_cast<int>(foo);
I've looked in the Standard, and it says that casts are expressions, not template functions as I thought.
This left me wondering: under the hood, are these casts just templates with privileged status, or are they keywords that happen to borrow the template syntax?
are they keywords that happen to borrow the template syntax?
This. Casts are implemented differently depending on the context they are used in – in general, they cannot be implemented as functions. For instance, static_cast is sometimes only a compile-time operation, no code is emitted for it. But other times (in particular when invoking constructors, casting in a type hierarchy or converting between layout-incompatible primitive types) it requires a runtime operation.
That said, you can implement your own functions that resemble the standard cast syntax (boost::lexical_cast does that).

C++11 and [17.5.2.1.3] Bitmask Types

The Standard allows one to choose between an integer type, an enum, and a std::bitset.
Why would a library implementor use one over the other given these choices?
Case in point, llvm's libcxx appears to use a combination of (at least) two of these implementation options:
ctype_base::mask is implemented using an integer type:
<__locale>
regex_constants::syntax_option_type is implemented using an enum + overloaded operators:
<regex>
The gcc project's libstdc++ uses all three:
ios_base::fmtflags is implemented using an enum + overloaded operators: <bits/ios_base.h>
regex_constants::syntax_option_type is implemented using an integer type,
regex_constants::match_flag_type is implemented using a std::bitset
Both: <bits/regex_constants.h>
AFAIK, gdb cannot "detect" the bitfieldness of any of these three choices so there would not be a difference wrt enhanced debugging.
The enum solution and integer type solution should always use the same space. std::bitset does not seem to make the guarantee that sizeof(std::bitset<32>) == std::uint32_t so I don't see what is particularly appealing about std::bitset.
The enum solution seems slightly less type safe because the combinations of the masks does not generate an enumerator.
Strictly speaking, the aforementioned is with respect to n3376 and not FDIS (as I do not have access to FDIS).
Any available enlightenment in this area would be appreciated.
The really surprising thing is that the standard restricts it to just three alternatives. Why shouldn't a class type be acceptable? Anyway…
Integral types are the simplest alternative, but they lack type safety. Very old legacy code will tend to use these as they are also the oldest.
Enumeration types are safe but cumbersome, and until C++11 they tended to be fixed to the size and range of int.
std::bitset may be have somewhat more type safety in that bitset<5> and bitset<6> are different types, and addition is disallowed, but otherwise is unsafe much like an integral type. This wouldn't be an issue if they had allowed types derived from std::bitset<N>.
Clearly enums are the ideal alternative, but experience has proven that the type safety is really unnecessary. So they threw implementers a bone and allowed them to take easier routes. The short answer, then, is that laziness leads implementers to choose int or bitset.
It is a little odd that types derived from bitset aren't allowed, but really that's a minor thing.
The main specification that clause provides is the set of operations defined over these types (i.e., the bitwise operators).
My preference is to use an enum, but there are sometimes valid reasons to use an integer. Usually ctype_base::mask interacts with the native OS headers, with a mapping from ctype_base::mask to the <ctype.h> implementation-defined constants such as _CTYPE_L and _CTYPE_U used for isupper and islower etc. Using an integer might make it easier to use ctype_base::mask directly with native OS APIs.
I don't know why libstdc++'s <regex> uses a std::bitset. When that code was committed I made a mental note to replace the integer types with an enumeration at some point, but <regex> is not a priority for me to work on.
Why would the standard allow different ways of implementing the library? And the answer is: Why not?
As you have seen, all three options are obviously used in some implementations. The standard doesn't want to make existing implementations non-conforming, if that can be avoided.
One reason to use a bitset could be that its size fits better than an enum or an integer. Not all systems even have a std::uint32_t. Maybe a bitset<24> will work better there?