What is the equivalent of cast for concepts? - c++

Consider a class A satisfies two concepts ConceptA and ConceptB. Let a function foo is overloaded for the two concepts:
void foo(ConceptA& arg);
void foo(ConceptB& arg);
A a;
fun(concept_cast<ConceptA>(a));
Note: This example uses the "Terse Notation" syntax proposed as part of N3701, §5
Is there something exist like concept_cast which allows users to select the overload?
Eg:
Lets say
ConceptA says T has to have a member function bar()
ConceptB says T has to have a member function baz()
and class A has both bar() and baz() member function
Its clearly ambiguous, but is there a way to explicitly select like we have static_cast for normal overloads?
Update: Accepted answer is more than 2 years old. Any update in c++17?

If one of the concepts is a more constrained version of the other, (e.g. everything that satisfies ConceptA will also satisfy ConceptB but not vice versa), then the most-constrained overload that A satisfies will be chosen.
If neither concept is more constrained than the other, then the two are considered to be ambiguous overloads. Given how you phrased the question, I expect you already knew this.
Regarding concept_cast, I don't think there's anything like that in the current proposal. At least not as of the Bristol meeting (Apr '13). I don't expect this to have changed as the current focus seems to be on making sure the core of the concepts-lite/constraints proposal is workable and acceptable to the committee.
There'll probably be some demand for explicitly picking overloaded template functions like that, and maybe such a cast is the right thing, but I'm not so sure. Consider that such a cast would only be useful for overload disambiguation, where as static_cast is a more general feature. The result of the concept_cast would be same as the original value outside the context of overload resolution!
Edit: Looking at the latest proposal (N3701), there's no provision for explicitly specifying which template function to instantiate.

Your claim that static_cast can be used to explicitly select a 'normal' overload is specious. It is possible to write the following in today's C++:
template<typename P, EnableIf<NullablePointer<P>>...>
void foo(P&);
template<typename It, EnableIf<Iterator<It>>...>
void foo(It&);
Assuming that NullablePointer and Iterator perform concept checking for the associated Standard concepts, then int* q; foo(q); has no hope of compiling because int* is both a model of NullablePointer and of Iterator (and neither concept subsumes the other). There's nothing obvious to static_cast to to help with that situation.
My example (that you can test for yourself) is extremely relevant because this kind of code is what Concepts Lite attempts to formalize. The overload set you're presenting is equivalent to:
template<typename A>
requires ConceptA<A>
void foo(A& arg);
template<typename B>
requires ConceptB<B>
void foo(B& arg);
Notice the similarity between the requires clauses and the EnableIf 'clauses'.

Related

Check existence of (global) function but disallow implicit conversion

Consider this simple check for whether a (global) function is defined:
template <typename T>
concept has_f = requires ( const T& t ) { Function( t ); };
// later use in MyClass<T>:
if constexpr ( has_f<T> ) Function( value );
unfortunately this allows for implicit conversions. This is obviously a big risk for mess-ups.
Question: How to check if Function( const T& t ) 'explicitly' exists?
Something like
if constexpr ( std::is_same_v<decltype( Function( t ) ), void> )
should be free of implict conversions, but I can't get it working.
Note: The point of the concept approach was to get rid of old 'detection patterns' and simplify.
Before explaining how to do this, I will explain why you shouldn't want to do any of this.
You mentioned "old 'detection patterns'" without adding any specifics as to what you are referring to. There are a fair number of idioms C++ users sometimes employ that can do something like detecting if a function takes a particular parameter. Which ones of these count as "detection patterns" by your reckoning is not known.
However, the vast majority of these idioms exist to serve a specific, singular purpose: to see if a particular function call with a given set of arguments is valid, legal C++ code. They don't really care if a function exactly takes T; testing for T specifically is just how a few of those idioms work to produce the important information. Namely whether you can pass a T to said function.
Looking for a specific function signature was almost always a means to an end, not the final goal.
Concepts, particularly requires expressions, is the end itself. It allows you to ask the question directly. Because really, you don't care if Function has a parameter that takes a T; you care whether Function(t) is legitimate code or not. Exactly how that happens is an implementation detail.
The only reason I can think of that someone might want to constrain a template on an exact signature (rather than an argument match) is to defeat implicit conversion. But you really shouldn't try to break basic language features like that. If someone writes a type that is implicitly convertible to another, they have the right to the benefits of that conversion, as defined by the language. Namely, the ability to use it in many ways as if it were that other type.
That is, if Function(t) is what your constrained template code is actually going to do, then the user of that template has every right to provide code that makes that compiler within the limits of the C++ language. Not within the limits of your personal ideas of what features are good or bad in that language.
Concepts are not like base classes, where you decide the exact signature for each method and the user must strictly abide by that. Concepts are patterns that constrain template definitions. Expressions in concept constraints are expressions that you expect to use in your template. You only put an expression in a concept if you plan on using it in your templates constrained by that concept.
You don't use a function signature; you call functions. So you constrain a concept on what functions can be called with which arguments. You're saying "you must let me do this", not "provide this signature".
That having been said... what you want is not generally possible ;)
There are several mechanisms that you might employ to achieve it, but none of them do exactly what you want in all cases.
The name of a function resolves to an overload set consisting of all of the functions that could be called. This name can be converted into a pointer to a specific function signature if and only if that signature is one of the functions in the overload set. So in theory, you might do this:
template <typename T>
concept has_f = requires () { static_cast<void (*)(T const&)>(&Function); };
However, because the name Function is not dependent on T (as far as C++ is concerned), it must be resolved during the first pass of two-phase name lookup for templates. That means any and all Function overloads you intend to care about have to be declared before has_f is defined, not merely instantiated with an appropriate T.
I think this is sufficient to declare that this is non-functional as a solution. Even if it worked though, it would only "work" given 3 circumstances:
Function is known/required to be an actual function, rather than a global object with an operator() overload. So if a provider of T wants to provide a global functor instead of a regular function (for any number of reasons) this method will not work, even though Function(t) is 100% perfectly valid, legitimate, and does none of those terrible implicit conversions that for some reason must be stopped.
The expression Function(t) is not expected to use ADL to find the actual Function to call.
Function is not a template function.
And not one of these possibilities has anything to do with implicit conversions. If you're going to call Function(t), then it's 100% OK for ADL to find it, template argument deduction to instantiate it, or for the user to fulfill this with some global lambda.
Your second-best bet is to rely on how overload resolution works. C++ only permits a single user-defined conversion in operator overloading. As such, you can create a type which will consume that one user-defined conversion in the function call expression in lieu of T. And that conversion should be a conversion to T itself.
You would use it like this:
template<typename T>
class udc_killer
{
public:
//Will never be called.
operator T const&();
};
template <typename T>
concept has_f = requires () { Function(udc_killer<T>{}); };
This of course still leaves the standard conversions, so you can't differentiate between a function taking a float if T is int, or derived classes from bases. You also can't detect if Function has any default parameters after the first one.
Overall, you're still not detecting the signature, merely call-ability. Because that's all you should care about to begin with.

What are the rules on using `void` to specialize a template?

Here's a stripped down illustration of what I just now wrote in the wild. I wasn't really expecting it to work, but it did.
#include <array>
template <typename T> using Foo = std::array<T,123>;
const int FOO_SIZE = std::tuple_size<Foo<void>>::value;
I wasn't sure using void to specialize Foo would compile, but it did, at least in this case.
I'm not confident that this solution is portable, or if it's just a fluke because the implementation of std::array happens to be compatible with the concept of an array-of-voids, which sounds like nonsense to me.
When can I, and when can I not, use void to specialize a template?
I can't find a really convincing specific set of standard wording without reproducing half the standard (:D) but I believe that this is well-defined.
The array constructor requires that T be MoveConstructible or MoveAssignable, and you're not going to be able to instantiate a std::array<void, N>.
But that's fine, because std::tuple_size doesn't need to do that, and it isn't specified to need to do that, and neither thing makes any other specific requirements that would render your code problematic.
However, this does not seem like useful code, and there is no general rule for when void can be used as a template argument. You have to look at the requirements for the specific thing you're using, in the specific context in which you're using it.
It seems on the face of it surprising that this compiles at all, since array of type void are explicitly excluded by the standard (11.3.4: 2 in the N4659 working draft linked) :
An array can be constructed from one of the fundamental types (except
void), from a pointer, from a pointer to member, from a class, from an
enumeration type, or from another array.
And std::array is typically implemented directly in terms of an array, so one would expect any attempt to use it to fail.
However C++ has generous rules regarding errors in template instantiation that are not directly required in the compilation of the actual usage. In this case, I believe the code is working - and portable - since the calculation of std::tuple_size<Foo<void>>::value does not actually instance Foo<void>, but I would view such as usage as perverse and something you should probably be avoiding since Foo<void> has no validity outside of such exceptions.

C++ concepts vs static_assert

What is exactly new in c++ concepts? In my understanding they are functionally equal to using static_assert, but in a 'nice' manner meaning that compiler errors will be more readable (as Bjarne Stroustup said you won't get 10 pages or erros, but just one).
Basically, is it true that everything you can do with concepts you can also achieve using static_assert?
Is there something I am missing?
tl;dr
Compared to static_asserts, concepts are more powerful because:
they give you good diagnostic that you wouldn't easily achieve with static_asserts
they let you easily overload template functions without std::enable_if (that is impossible only with static_asserts)
they let you define static interfaces and reuse them without losing diagnostic (there would be the need for multiple static_asserts in each function)
they let you express your intents better and improve readability (which is a big issue with templates)
This can ease the worlds of:
templates
static polymorphism
overloading
and be the building block for interesting paradigms.
What are concepts?
Concepts express "classes" (not in the C++ term, but rather as a "group") of types that satisfy certain requirements. As an example you can see that the Swappable concept express the set of types that:
allows calls to std::swap
And you can easily see that, for example, std::string, std::vector, std::deque, int etc... satisfy this requirement and can therefore be used interchangeably in a function like:
template<typename Swappable>
void func(const Swappable& a, const Swappable& b) {
std::swap(a, b);
}
Concepts always existed in C++, the actual feature that will be added in the (possibly near) future will just allow you to express and enforce them in the language.
Better diagnostic
As far as better diagnostic goes, we will just have to trust the committee for now. But the output they "guarantee":
error: no matching function for call to 'sort(list<int>&)'
sort(l);
^
note: template constraints not satisfied because
note: `T' is not a/an `Sortable' type [with T = list<int>] since
note: `declval<T>()[n]' is not valid syntax
is very promising.
It's true that you can achieve a similar output using static_asserts but that would require different static_asserts per function and that could get tedious very fast.
As an example, imagine you have to enforce the amount of requirements given by the Container concept in 2 functions taking a template parameter; you would need to replicate them in both functions:
template<typename C>
void func_a(...) {
static_assert(...);
static_assert(...);
// ...
}
template<typename C>
void func_b(...) {
static_assert(...);
static_assert(...);
// ...
}
Otherwise you would loose the ability to distinguish which requirement was not satisfied.
With concepts instead, you can just define the concept and enforce it by simply writing:
template<Container C>
void func_a(...);
template<Container C>
void func_b(...);
Concepts overloading
Another great feature that is introduced is the ability to overload template functions on template constraints. Yes, this is also possible with std::enable_if, but we all know how ugly that can become.
As an example you could have a function that works on Containers and overload it with a version that happens to work better with SequenceContainers:
template<Container C>
int func(C& c);
template<SequenceContainer C>
int func(C& c);
The alternative, without concepts, would be this:
template<typename T>
std::enable_if<
Container<T>::value,
int
> func(T& c);
template<typename T>
std::enable_if<
SequenceContainer<T>::value,
int
> func(T& c);
Definitely uglier and possibly more error prone.
Cleaner syntax
As you have seen in the examples above the syntax is definitely cleaner and more intuitive with concepts. This can reduce the amount of code required to express constraints and can improve readability.
As seen before you can actually get to an acceptable level with something like:
static_assert(Concept<T>::value);
but at that point you would loose the great diagnostic of different static_assert. With concepts you don't need this tradeoff.
Static polymorphism
And finally concepts have interesting similarities to other functional paradigms like type classes in Haskell. For example they can be used to define static interfaces.
For example, let's consider the classical approach for an (infamous) game object interface:
struct Object {
// …
virtual update() = 0;
virtual draw() = 0;
virtual ~Object();
};
Then, assuming you have a polymorphic std::vector of derived objects you can do:
for (auto& o : objects) {
o.update();
o.draw();
}
Great, but unless you want to use multiple inheritance or entity-component-based systems, you are pretty much stuck with only one possible interface per class.
But if you actually want static polymorphism (polymorphism that is not that dynamic after all) you could define an Object concept that requires update and draw member functions (and possibly others).
At that point you can just create a free function:
template<Object O>
void process(O& o) {
o.update();
o.draw();
}
And after that you could define another interface for your game objects with other requirements. The beauty of this approach is that you can develop as many interfaces as you want without
modifying your classes
require a base class
And they are all checked and enforced at compile time.
This is just a stupid example (and a very simplistic one), but concepts really open up a whole new world for templates in C++.
If you want more informations you can read this nice article on C++ concepts vs Haskell type classes.

How will Concepts-Lite interact with variadic templates?

I watched Bjarne Strustrup's talk in Going Native 2013 and he gives the following example for the upcoming concepts-lite feature of C++.
void sort(Container& c); // terse notation
// Expands to
template <Container __Cont>
void sort(__Cont& c); // shorthand notation
// Expands to
template <typename __Cont>
requires Container<__Cont>()
void sort(__Cont & c);
My question is how will this work with variadic templates?
Say I want to define a variadic maximum function using a Comparable concept. Will the following syntax be accepted?
auto maximum(Comparable a)
{
return a;
}
auto maximum(Comparable c, Comparable... rest)
{
return std::max(a, maximum(rest...));
}
If so will Comparable... mean that all the elements in the parameter pack are the same type or just that they are all Comparable types so that the pack may include both int and string? (which are both comparable but not to each other)
Curious minds want to know.
I believe the intention of the terse format is to require all elements in the pack must be of the same type. This is derived from the example in n3701 §5.3, which states that
void sort(Random_access_iterator p, Random_access_iterator q);
should be equivalent to
template<Random_access_iterator __Ran>
void sort(__Ran p, __Ran q);
because
"By default, if you use the same constrained parameter
type name for two arguments, the types of those arguments must be the same.
We chose to make repeated use of a constrained parameter type name imply
“same type” because that (in most environments) is the most common case,
it would be odd to have an identifier used twice in a scope have two different
meanings, and the aim here is to optimize for terse notation of the simplest case."
But I don't see how it can be expanded into your maximum with the current ('14) template syntax. In proposed change of standard wording in n3701 it only talked about the simple case
§7.1.6.5 Constrained type specifiers [dcl.spec.constrained]
...
The first use of concept-name or partial-concept-id within a scope binds that
name to the placeholder type so that subsequent uses of the same name refer to
the same type.
But it doesn't explain the interaction of variadics. Maybe need to wait for the 3rd revision to clarify this.
I don't know if N3580 is the latest version of the concept paper but in 4.5.1 it seems to describe how type requirements can be used with variadic argument lists. It seems that
template <Comparable... T>
auto maximum(T... values) -> <return-type-goes-here>
would require that each of the arguments satisfies the Comparable requirement but there is no restriction that the types T... are all the same. This requirement would need to be imposed separately. Off-hand, the only way I'd know how to impose the same type requirement is the same approach as in C++11 but the concepts facilities may have a better approach.

Hypothetical, formerly-C++0x concepts questions

(Preamble: I am a late follower to the C++0x game and the recent controversy regarding the removal of concepts from the C++0x standard has motivated me to learn more about them. While I understand that all of my questions are completely hypothetical -- insofar as concepts won't be valid C++ code for some time to come, if at all -- I am still interested in learning more about concepts, especially given how it would help me understand more fully the merits behind the recent decision and the controversy that has followed)
After having read some introductory material on concepts as C++0x (until recently) proposed them, I am having trouble wrapping my mind around some syntactical issues. Without further ado, here are my questions:
1) Would a type that supports a particular derived concept (either implicitly, via the auto keyword, or explicitly via concept_maps) also need to support the base concept indepdendently? In other words, does the act of deriving a concept from another (e.g. concept B<typename T> : A<T>) implicitly include an 'invisible' requires statement (within B, requires A<T>;)? The confusion arises from the Wikipedia page on concepts which states:
Like in class inheritance, types that
meet the requirements of the derived
concept also meet the requirements of
the base concept.
That seems to say that a type only needs to satisfy the derived concept's requirements and not necessarily the base concept's requirements, which makes no sense to me. I understand that Wikipedia is far from a definitive source; is the above description just a poor choice of words?
2) Can a concept which lists typenames be 'auto'? If so, how would the compiler map these typenames automatically? If not, are there any other occasions where it would be invalid to use 'auto' on a concept?
To clarify, consider the following hypothetical code:
template<typename Type>
class Dummy {};
class Dummy2 { public: typedef int Type; };
auto concept SomeType<typename T>
{
typename Type;
}
template<typename T> requires SomeType<T>
void function(T t)
{}
int main()
{
function(Dummy<int>()); //would this match SomeType?
function(Dummy2()); //how about this?
return 0;
}
Would either of those classes match SomeType? Or is a concept_map necessary for concepts involving typenames?
3) Finally, I'm having a hard time understanding what axioms would be allowed to define. For example, could I have a concept define an axiom which is logically inconsistent, such as
concept SomeConcept<typename T>
{
T operator*(T&, int);
axiom Inconsistency(T a)
{
a * 1 == a * 2;
}
}
What would that do? Is that even valid?
I appreciate that this is a very long set of questions and so I thank you in advance.
I've used the most recent C++0x draft, N2914 (which still has concepts wording in it) as a reference for the following answer.
1) Concepts are like interfaces in that. If your type supports a concept, it should also support all "base" concepts. Wikipedia statement you quote makes sense from the point of view of a type's client - if he knows that T satisfies concept Derived<T>, then he also knows that it satisfies concept Base<T>. From type author perspective, this naturally means that both have to be implemented. See 14.10.3/2.
2) Yes, a concept with typename members can be auto. Such members can be automatically deduced if they are used in definitions of function members in the same concept. For example, value_type for iterator can be deduced as a return type of its operator*. However, if a type member is not used anywhere, it will not be deduced, and thus will not be implicitly defined. In your example, there's no way to deduce SomeType<T>::Type for either Dummy or Dummy1, as Type isn't used by other members of the concept, so neither class will map to the concept (and, in fact, no class could possibly auto-map to it). See 14.10.1.2/11 and 14.10.2.2/4.
3) Axioms were a weak point of the spec, and they were being constantly updated to make some (more) sense. Just before concepts were pulled from the draft, there was a paper that changed quite a bit - read it and see if it makes more sense to you, or you still have questions regarding it.
For your specific example (accounting for syntactic difference), it would mean that compiler would be permitted to consider expression (a*1) to be the same as (a*2), for the purpose of the "as-if" rule of the language (i.e. the compiler permitted to do any optimizations it wants, so long as the result behaves as if there were none). However, the compiler is not in any way required to validate the correctness of axioms (hence why they're called axioms!) - it just takes them for what they are.