static_assert seems to be a very nice feature together with templates.
However, I have trouble finding functions in the standard library for doing various tests at compile time.
For example, I am looking for a function to check whether a type is a subtype of another one. boost::is_base_of does the job, however, is a comparable function in std, so I do not need to rely on boost.
Basically, is there a good source for a list of functions which can be used in static_assert and are contained in the standard library of C++11?
When is static_assert executed? Can I put it anywhere in a template and it is evaluated for each template instanciation? Could it be used to constrain template parameters to be a specific subtype of a class?
Take a look at the final C++11 draft, section 20.7, particularly the <type_traits> header.
What you are asking is: std::is_base_of<base, derived>::value;
Regarding your question: static_assert can be evaluated whenever the compiler sees fit, but it will usually:
In a template: if the expression uses dependent names, in instatiation time; else, in definition time.
Out of template: in definition time.
In addition to #rodrigo’s answer (he was faster …),
When is static assert executed? Can I put it anywhere in a template and it is evaluated for each template instanciation? Could it be used to constrain template parameters to be a specific subtype of a class?
Unfortunately, no. For instance, a static_assert(false, "bummer"); is always executed, no matter the template. This in particular fails if you want to (partially) specialise a template.
The standard (§7.4) says:
[If the condition to static_assert is false] the program is ill-formed, and the resulting diagnostic message (1.4) shall include the text of the string-literal, […]
Which is unfortunately quite unspecific but this lack of specificity is in fact exactly how static_assert behaves when it’s not dependent on a template type.
You need to make the condition in a static_assert depend on the template argument to bind its execution to the particular template argument.
So the following would fail:
template <typename T>
struct some_type {
static_assert(false, "T must be a pointer type");
};
template <typename T>
struct some_type<T*> {
// …
};
Finally, I heartily recommend you read Marthino’s article on More type traits which details this process more, and gives hints on how to solve many trait-related problems elegantly.
Related
C++20 introduces concepts, which allows us to specify in the declaration of a template that the template parameters must provide certain capabilities. If a template is instantiated with a type that does not satisfy the constraints, compilation will fail at instantiation instead of while compiling the template's body and noticing an invalid expression after substitution.
This is great, but it begs the question: is there a way to have the compiler look at the template body, before instantiation (i.e. looking at it as a template and not a particular instantiation of a template), and check that all the expressions involving template parameters are guaranteed by the constraints to exist?
Example:
template<typename T>
concept Fooer = requires(T t)
{
{ t.foo() };
};
template<Fooer F>
void callFoo(F&& fooer)
{
fooer.foo();
}
The concept prevents me from instantiating callFoo with a type that doesn't support the expression that's inside the template body. However, if I change the function to this:
template<Fooer F>
void callFoo(F&& fooer)
{
fooer.foo();
fooer.bar();
}
This will fail if I instantiate callFoo with a type that defines foo (and therefore satisfies the constraints) but not bar. In principal, the concept should enable the compiler to look at this template and reject it before instantiation because it includes the expression fooer.bar(), which is not guaranteed by the constraint to exist.
I assume there's probably backward compatibility issues with doing this, although if this validation is only done with parameters that are constrained (not just typename/class/etc. parameters), it should only affect new code.
This could be very useful because the resulting errors could be used to guide the design of constraints. Write the template implementation, compile (with no instantiations yet), then on each error, add whatever requirement is needed to the constraint. Or, in the opposite direction, when hitting an error, adjust the implementation to use only what the constraints provide.
Do any compilers support an option to enable this type of validation, or is there a plan to add this at any point? Is it part of the specification for concepts to do this validation, now or in the future?
Do any compilers support an option to enable this type of validation, or is there a plan to add this at any point? Is it part of the specification for concepts to do this validation, now or in the future?
No, no, and no.
The feature you're looking for is called definition checking. That is, the compiler checks the definition of the template at the point of its definition based on the provided concepts, and issues errors if anything doesn't validate. This is how, for instance, Rust Traits, Swift Protocols, and Haskell Typeclasses work.
But C++ concepts don't work like that, and it seems completely infeasible to ever add support for such a thing given that C++ concepts can be arbitrary expressions rather than function signatures (as they are in other languages).
The best you can do is thoroughly unit test your templates with aggressively exotic types that meet your requirements as minimally as possible (the term here is archetype) and hope for the best.
TL;DR: no.
The design for the original C++11 concepts included validation. But when that was abandoned, the new version was designed to be much more narrow in scope. The new design was originally built on constexpr boolean conditions. The eventual requires expression was added to make these boolean checks easier to write and to bring some sanity to relationships between concepts.
But the fundamentals of the design of C++20 concepts makes it basically impossible to do full validation. Even if a concept is built entirely out of atomic requires expressions, there isn't a way to really tell if an expression is being used exactly in the code the way it is in the requires expression.
For example, consider this concept:
template<typename T, typename U>
concept func_to_u = requires(T const t)
{
{t.func()} -> std::convertible_to<U>;
};
Now, let's imagine the following template:
template<typename T, typename U> requires func_to_u<T, U>
void foo(T const &t)
{
std::optional<U> u(std::in_place, t.func());
}
If you look at std::optional, you find that the in_place_t constructor doesn't take a U. So... is this a legitimate use of that concept? After all, the concept says that code guarded by this concept will call func() and will convert the result to a U. But this template does not do this.
It instead takes the return type, instantiates a template that is not guarded by func_to_u, and that template does whatever it wants. Now, it turns out that this template does perform a conversion operation to U.
So on the one hand, it's clear that our code does conform to the intent of func_to_u. But that is only because it happened to pass the result to some other function that conformed to the func_to_u concept. But that template had no idea it was subject to the limitations of convertible_to<U>.
So... how is the compiler supposed to detect whether this is OK? The trigger condition for failure would be somewhere in optional's constructor. But that constructor is not subject to the concept; it's our outer code that is subject to the concept. So the compiler would basically have to unwind every template your code uses and apply the concept to it. Only it wouldn't even be applying the whole concept; it would just be applying the convertible_to<U> part.
The complexity of doing that quickly spirals out of control.
I started experimenting with the C++20 feature of concepts and was very pleased when I realized that it is possible to partially explicitly provide template arguments for concepts. I read the cppreference article and did not find that mentioned there.
But then I realized something strange: the order of specification of template arguments is reversed to what I would have expected. When providing one explicite template argument, it replaces the second template in the template list:
#include <concepts>
#include <type_traits>
/// Concept in order to deduce if sth. is base of sth else
template <typename Impl, typename Base> //XXX: here the order of Impl and Base are not
concept Implements = std::is_base_of_v<std::remove_reference_t<Base>, // what I would've expected.
std::remove_reference_t<Impl>>;
/// Example Base class impl
struct BaseExample {};
/// Implementation of BaseExample
struct ImplExample : BaseExample {};
/// Function in which the concept is applied
template <Implements<BaseExample>... Baes> void f(Baes &&... ) {}//} ((void)b, ...); }
int main() {
(void) std::is_base_of_v<BaseExample, std::remove_reference_t<ImplExample &&>>; //< true
(void) std::is_base_of_v<BaseExample, std::remove_reference_t<ImplExample&>>; //< true
f(ImplExample{}, ImplExample{});
}
From my point of view the possibility to partially provide explicit template arguments makes sense, as the argument against partial template specification for classes do not apply here and make concepts more general. Now I wonder:
Will partial explicit template specifications (likely) be allowed when the standard is released?
Will this order of specifications likely stay the same or is this a bug?
How would I answer this question for myself? From what I understand the c++20 standard is not ready by now and I found a list of C++ Standard Committee Papers, of which I briefly searched the headlines of the ones proposed in 2020 for 'concept'. Is checking these papers the way to go, or is there an accessible single document which combines the points the authors currently agreed upon?
The code can be found here.
edit
After posting this I checked the behavior when three template arguments are specified. It looks like I misinterpreted the specification order: The first argument is 'held free' to contain the argument to be checked, and the explicit specifications start with the second argument. This can be seen here.
Even though I figured out the reasoning behind the order of specification I would be very interested in the answers to questions above.
Yes, partial-concept-ids are surely a C++20 thing. The special status of the first argument, while surprising, allows cases like std::constructible_from which is declared as
template<class T,class ...Args>
concept constructible_from=…;
std::constructible_from<int,int> is a type-constraint that requires that whatever it introduces be constructible from two int arguments. However, it can also be an expression, in which case it reports whether an int can be constructed from an int (spoilers: true), but that potential confusion exists regardless of the argument order.
If T had to go at the end, there would be no way of using such a concept: only template argument deduction or default template arguments can supply values for a template parameter beyond a parameter pack, and neither of those applies here.
Every mailing posted at the papers site you linked includes the latest draft of the standard, and alternate mailings include annotations as to what papers were adopted. Or you can just visit the draft’s repository (at least if you’re happy reading LaTeX).
C++11
14.8.2 - Template Argument Deduction - [temp.deduct]
7 The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. The expressions include not only constant expressions such as those that appear in array bounds or as nontype template arguments but also general expressions (ie. non-constant expressions) inside sizeof, decltype, and other contexts that allow non-constant expressions.
C++14
14.8.2 - Template Argument Deduction - [temp.deduct]
7 The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. The expressions include not only constant expressions such as those that appear in array bounds or as nontype template arguments but also general expressions (ie. non-constant expressions) inside sizeof, decltype, and other contexts that allow non-constant expressions. The substitution proceeds in lexical order and stops when a condition that causes deduction to fail is encountered.
The added sentence explicitly states the order of substitution when dealing with template parameters in C++14.
The order of substitution is something that most often isn't given a lot of attention. I have yet to find a single paper on why this matters. Maybe this is because C++1y hasn't been fully standardized yet, but I'm assuming such a change must have been introduced for a reason.
The question:
Why, and when, does the order of template argument substitution matter?
As stated C++14 explicitly says that the order of template argument substitution is well-defined; more specifically it will be guaranteed to proceed in "lexical order and halt whenever a substitution causes the deduction to fail.
Compared to C++11 it will be much easier to write SFINAE-code that consists of one rule depending on another in C++14, we will also move away from cases where undefined ordering of template substitution can make our entire application suffer from undefined-behaviour.
Note: It's important to note that the behavior described in C++14 has always been the intended behavior, even in C++11, just that it hasn't been worded in such an explicit way.
What is the rationale behind such change?
The original reason behind this change can be found in a defect report originally submitted by Daniel Krügler:
C++ Standard Core Language Defect Reports and Accepted Issues, Revision 88
1227. Mixing immediate and non-immediate contexts in deduction failure
FURTHER EXPLANATION
When writing SFINAE we as developers depend on the compiler to find any substitution that would yield an invalid type or expression in our template when used. If such invalid entity is found we'd like to disregard whatever the template is declaring and move on to hopefully find a suitable match.
Substitution Failure Is Not An Error, but a mere.. "aw, this didn't work.. please move on".
The problem is that potential invalid types and expressions are only looked for in the immediate context of the substitution.
14.8.2 - Template Argument Deduction - [temp.deduct]
8 If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments.
[ Note: Access checking is done as part of the substitution process. --end note ]
Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.
[ Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the "immediate context" and can result in the program being ill-formed. --end note]
In other words a substitution that occurs in a non-immediate context will still render the program ill-formed, which is why the order of template substitutions is important; it can change the whole meaning of a certain template.
More specifically it can be the difference between having a template which is usable in SFINAE, and a template which isn't.
SILLY EXAMPLE
template<typename SomeType>
struct inner_type { typedef typename SomeType::type type; };
template<
class T,
class = typename T::type, // (E)
class U = typename inner_type<T>::type // (F)
> void foo (int); // preferred
template<class> void foo (...); // fallback
struct A { };
struct B { using type = A; };
int main () {
foo<A> (0); // (G), should call "fallback "
foo<B> (0); // (H), should call "preferred"
}
On the line marked (G) we want the compiler to first check (E) and if that succeeds evaluate (F), but before the standard change discussed in this post there was no such guarantee.
The immediate context of the substitutions in foo(int) includes;
(E) making sure that the passed in T has ::type
(F) making sure that inner_type<T> has ::type
If (F) is evaluated even though (E) results in an invalid substitution, or if (F) is evaluated before (E) our short (silly) example won't make use of SFINAE and we will get an diagnostic saying that our application is ill-formed.. even though we intended for foo(...) to be used in such case.
Note: Notice that SomeType::type is not in the immediate context of the template; a failure in the typedef inside inner_type will render the application ill-formed and prevent the template from making use of SFINAE.
What implications will this have on code development in C++14?
The change will dramatically ease the life of language-lawyers trying to implement something which is guaranteed to be evaluated in a certain way (and order), no matter what conforming compiler they are using.
It will also make template argument substitution behave in a more natural way to non-language-lawyers; having the substitution occur from left-to-right is far more intuitive than erhm-like-any-way-the-compiler-wanna-do-it-like-erhm-....
Isn't there any negative implication?
The only thing I can think of is that since the order of substitution will occur from left-to-right a compiler is not permitted to handle multiple substitutions at once using an asynchronous implementation.
I have yet to stumble across such implementation, and I doubt that it would result in any major performance gain, but at least the thought (in theory) kinda fits on the "negative" side of things.
As an example: A compiler will not be able to use two threads that simultaneously does substitutions when instantating a certain template without any mechanism to act like the substitutions that occured after a certain point never happened, if that is required.
The story
Note: An example that could have been taken from real life will be presented in this section to describe when and why the order of template argument substitution matters. Please let me know (using the comment section) if anything is not clear enough, or maybe even wrong.
Imagine that we are working with enumerators and that we'd like a way to easily obtain the underlying value of the specified enumeration.
Basically we are sick and tired of always having to write (A), when we would ideally want something closer to (B).
auto value = static_cast<std::underlying_type<EnumType>::type> (SOME_ENUM_VALUE); // (A)
auto value = underlying_value (SOME_ENUM_VALUE); // (B)
THE ORIGINAL IMPLEMENTATION
Said and done, we decide to write an implementation of underlying_value looking as the below.
template<class T, class U = typename std::underlying_type<T>::type>
U underlying_value (T enum_value) { return static_cast<U> (enum_value); }
This will ease our pain, and seems to do exactly what we want; we pass in an enumerator, and get the underlying value back.
We tell ourselves that this implementation is awesome and ask a colleague of ours (Don Quixote) to sit down and review our implementation before pushing it out into production.
THE CODE REVIEW
Don Quixote is an experienced C++ developer that has a cup of coffee in one hand, and the C++ standard in the other. It's a mystery how he manages to write a single line of code with both hands busy, but that's a different story.
He reviews our code and comes to the conclusion that the implementation is unsafe, we need to guard std::underlying_type from undefined-behaviour since we can pass in a T which is not of enumeration type.
20.10.7.6 - Other Transformations - [meta.trans.other]
template<class T> struct underlying_type;
Condition: T shall be an enumeration type (7.2)
Comments: The member typedef type shall name the underlying type of T.
Note: The standard specifies a condition for underlying_type, but it doesn't go any further to specifiy what will happen if it's instantiated with a non-enum. Since we don't know what will happen in such case the usage falls under undefined-behavior; it could be pure UB, make the application ill-formed, or order edible underwear online.
THE KNIGHT IN SHINING ARMOUR
Don yells something about how we always should honor the C++ standard, and that we should feel tremendous shame for what we have done.. it's unacceptable.
After he has calmed down, and had a few more sips of coffee, he suggests that we change the implementation to add protection against instantiating std::underlying_type with something which isn't allowed.
template<
typename T,
typename = typename std::enable_if<std::is_enum<T>::value>::type, // (C)
typename U = typename std::underlying_type<T>::type // (D)
>
U underlying_value (T value) { return static_cast<U> (value); }
THE WINDMILL
We thank Don for his discoveries and are now satisfied with our implementation, but only until we realize that the order of template argument substitution isn't well-defined in C++11 (nor is it stated when the substitution will stop).
Compiled as C++11 our implementation can still cause an instantiation of std::underlying_type with a T that isn't of enumeration type because of two reasons:
The compiler is free to evaluate (D) before (C) since the substitution order isn't well-defined, and;
even if the compiler evaluates (C) before (D), it's not guaranteed that it won't evaluate (D), C++11 doesn't have a clause explicitly saying when the substitution chain must stop.
The implementation by Don will be free from undefined-behavior in C++14, but only because C++14 explicitly states that the substitution will proceed in lexical order, and that it will halt whenever a substitution causes deduction to fail.
Don might not be fighting windmills on this one, but he surely missed a very important dragon in the C++11 standard.
A valid implementation in C++11 would need to make sure that no matter the order in which the substitution of template parameters occur the instantation of std::underlying_type won't be with an invalid type.
#include <type_traits>
namespace impl {
template<bool B, typename T>
struct underlying_type { };
template<typename T>
struct underlying_type<true, T>
: std::underlying_type<T>
{ };
}
template<typename T>
struct underlying_type_if_enum
: impl::underlying_type<std::is_enum<T>::value, T>
{ };
template<typename T, typename U = typename underlying_type_if_enum<T>::type>
U get_underlying_value (T value) {
return static_cast<U> (value);
}
Note: underlying_type was used because it's a simple way to use something in the standard against what is in the standard; the important bit is that instantiating it with a non-enum is undefined behavior.
The defect-report previously linked in this post uses a much more complex example which assumes extensive knowledge about the matter. I hope this story is a more suitable explanation for those who are not well read up on the subject.
In a template I have some functions which are only valid for certain template types. GCC seems to be happy with this, but I'm not sure it is valid. Unlike typical SFINAE the function itself is not a template.
template<typename T>
struct generic {
T item;
void get_limited() {
item.limited();
}
};
Provided I don't call get_limited, is it okay to instantiate this class with a type that does not implement limited?
If no, how can I solve this? I have a generic container class where certain features are enabled based on the allocate it is storing (so not directly on the type as above, but still a template parameter).
Template functions are instantiated on demand, so if there is no use of the function it need not be correct, at least for some possible instantiations. The standard does state that if a template is not valid for any instantiating type, the program is ill-formed (although the compiler is not required to diagnose it) even if it is never instantiated.
This feature is used in the standard library in different parts, where the requirements of a single function might be stricter than the general requirements that the template places on the instantiating types. For example, in the case of std::map, in general, the value type does not need to be default constructible, but if you want to use operator[] then it needs to be, since that operator might need to create an empty element if the key is not present.
Is there a way to do something like the following in C++
template<typename TAnimal>
bool can_eat(TAnimal& animal) where bool TAnimal::IsAlive() exists
{
return !animal.IsAlive();
}
//...
Duck duck;
assert(can_eat(duck) == true); //compiles
Wood wood;
can_eat(wood); // fails to compile because wood doesn't have IsAlive()
The explicit interface, in my opinion, makes it more clear what the function expects. However, I don't want to create an actual interface class (very tedious).
Do not use enable_if to enforce your requirements. Using enable_if will make the function 'disappear', which can be quite confusing for the user. Typical symptom is an error message such as error: no matching function for call to expression. That doesn't exactly convey to the user that a requirement violated.
You should instead enforce your requirements using static_assert, assuming C++0x. If you're using C++03, whether you should be using an emulation of static_assert (e.g. Boost's STATIC_ASSERT) or not is a toss-up since that usually means trading one error message for the other.
Contrast:
// SFINAE for types that do not decay to int
template<
typename T
, typename = typename std::enable_if<
std::is_same<
typename std::decay<T>::type
, int
>::value
>::type
>
void
f(T&&)
{}
// using static assert instead
template<
typename T
>
void
g(T&&)
{
static_assert( std::is_same<typename std::decay<T>::type, int>::value
, "Constraints violation" );
}
Using GCC I get the following error for doing f("violation") (both messages come with filename and line number):
error: no matching function for call to 'f(const char [10])'
On the other hand, g("violation") yields:
error: static assertion failed: "Constraints violation"
Now imagine that you use clear, explicit messages in your assertions such as foo: parameter type must be CopyConstructible inside template foo.
With that said, SFINAE and static_assert are somewhat antagonistic, thus having both explicit constraint violation messages and clever overloads isn't always possible and/or easy.
What you want to do is easily achieved using Boost.ConceptCheck. It does however require to write out-of-line code: the constraints class. I also don't think it uses static_assert where available, so the error messages might not be as nice. This could be changed in the future.
Another possibility is to use static_assert + type traits. What's interesting with that approach is that with C++0x the library comes with a bevy of useful traits, which you can use right out of the box without writing out-of-line code. Even more interesting is that the use of traits is not limited to writing constraints, they can also be used with SFINAE to make clever overloads.
However, there is no trait that is available off-hand to check whether a type supports a particular member of operation, possibly due to the way C++ handles the names of functions. We can't use something like has_member<T, &T::member_to_test_for> either because that would only make sense if the member we were testing for existed in the first place (disregarding things like overloads and the fact that we also need to pass the signature of the member to the trait).
Here's how to transform an arbitrary expression into a trait:
template<typename T>
struct void_ {
typedef void type;
};
template<typename T>
struct trait {
private:
typedef char yes[1];
typedef char no[2];
template<typename U>
static
yes&
test(U&&
, typename void_<decltype( std::declval<U&>().member() )>::type* = 0);
static
no&
test(...);
public:
static constexpr bool value = sizeof test(std::declval<T>()) == sizeof(yes);
};
Notice how sizable this is. Writing a Boost.ConceptCheck constraints class might be easier (but remember, not reusable for SFINAE).
The arbitrary expression is std::declval<U&>().member(). Here, the requirements are that given an lvalue reference of U (or T for the case where the trait is true, if you will), then calling member() on it is valid.
You could also check that the type of that expression (i.e. the result type of whatever overload of member has been picked for this expression) is convertible to a type (do not check whether it is that type; that's too restrictive for no good reason). That would inflate the trait however, again making this in favour of a constraints class.
I do not know of a way to make a static_assert part of the signature of a function template (this seems to be something you want), but it can appear inside a class template. Boost.ConceptCheck doesn't support that either.
This is something that concepts were intended to solve.
Concepts were a proposed addition to the latest C++ standard, but were dropped because the commitee wasn't convinced that they were solid enough to include in the language. See what Herb Sutter wrote about their exclusion from the standard.
Technically, concepts are unneeded, as template simply use whatever they can (i.e. lose the where clause, and you have what you're asking for). If the required method isn't there at compile time, then the code simply will not compile. But concepts would give the coder more explicit control over the type's interface, and would give much more reasonable error message than currently provided by most compilers.
Boost offers BOOST_STATIC_ASSERT for this. The just recently approved version of the C++ standard will offer a built-in version of a static_assert macro.
enable_if, on the other hand, isn’t really well suited for this. It can be used but the primary purpose of enable_if is to distinguish between otherwise ambiguous overloads.
where void TAnimal::IsAlive() exists
I assume you mean bool TAnimal::IsAlive()? If so, C++ already does what you are asking. If Duck has the IsAlive() method, then this will compile:
Duck duck;
assert(can_eat(duck) == true); //compiles
If Wood does not have the IsAlive() method, this will not compile:
Wood wood;
can_eat(wood); // fails to compile because wood doesn't have IsAlive()
That's what you're asking for right?
You don't have to do anything--just omit the hypothetical "where ... exists" from your example and it is normal C++ code that works.
If you insist on having the function be available only under some condition, you might try combining boost::enable_if with has_member from here: http://lists.boost.org/Archives/boost/2002/03/27229.php
The idea being that you would only allow the template function to be instantiated if some condition was met...but since SFINAE the compiler is basically going to do that for you already in the case where the condition is the same as the actual compile-time needs of the function (as in your example).
As others have said this will just work. it won't be able to instantiate the template if the function does not exist.
The boost library contains some classes to assist with this kind of thing though, for example enable_if which can be used to only "enable" a template where a condition is true. There is also the type traits library which is kind of related, you might be able to use this to determine at compile time if the function you want to call exists.
I have to admit I've not used any of this myself, but it looks to me like you should be able to use it to achieve what you want...