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...
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.
Let's consider a type trait of the following form:
template <class T>
struct is_instantiable
{
static constexpr bool value = /* something */;
};
template <class T>
inline constexpr bool is_instantiable_v = is_instantiable<T>::value;
which would detect whether an entity of type T can be instantiated.
Currently the standard library already has traits like is_constructible (but it requires the arguments from which the object is constructed). I am wondering:
Whether an is_instantiable type trait would be any useful?
Would it allow things that are currently problematic with is_constructible?
How would it even be defined/implemented (it's ok if it requires some compiler magic)?
Currently I have no idea whether such a thing would be any useful? (if you have any interesting use case in mind where is_constructible is limiting, that would be awesome).
Let's think about this conversely.
I'm assuming that by something that cannot be instantiated you mean something that doesn't have a single valid constructor and is not an in-built type.
As far as I see, the only way you can give anything a type, an instance of which cannot be constructed, is by casting (using a reinterpret_cast?).
Writing code like that is a horrible decision, in my opinion, but I suppose it could theoretically occur.
I guess, a usage case would be a situation where you are expecting that an object you are dealing with might have been produced by such a cast, and you want to know whether that's the case.
It's definitely an esoteric question to ask the compiler, and I don't see how this information can be used productively, nor how you could implement this trait.
From here it seems to me that the std::function has no function_type or equivalent member type to export the actual type used to initialize it.
It has result_type, argument_type, as well as first_argument_type and second_argument_type, but nothing like the type above mentioned.
Why it doesn't offer such a type as part of its interface?
There will be for sure a good reason for that, but I can't figure out what's that reason, so I'm just curious to find it out.
For I know the first question will be why do you need it, well, imagine that I want to do something like std::is_same<F1::function_type, F2::function_type>::value to check if their underlying types are the same in a sfinae evaluation, where it's fine if they contain different functions as long as the signs are the same.
I admit that it doesn't make much sense, to be honest the question is just for the sake of curiosity.
EDIT
As noted by #Brian in the comments of his answer, I misused the term initialize when I wrote:
to export the actual type used to initialize it
What I'm interested in is the template argument indeed.
As an example, for a std::function<void(S&, int)> (where S is a struct), function_type would be void(S&, int).
I think you're asking the wrong question. The right question is: why should there be such a member type?
If, say, you write a function template that can accept any specialization of std::function, then the template parameter will already be immediately available to you:
template <typename T>
void f(std::function<T> F) {
// you wouldn't write decltype(F)::function_type here; you'd just write T
}
The more inconvenient case is the one in which you have some function like
template <typename Callable>
void f(Callable C);
Here, you have no guarantee that Callable is a std::function specialization, so even if std::function<T> had typedef T function_type, you wouldn't want to access Callable::function_type for an arbitrary callable. So it wouldn't be of any use here.
The right question is: why do some standard library classes expose their template parameters, for example, containers of T (which have typedef T value_type)? The answer is that the standard has a specific set of requirements that the container types have to satisfy, which reflects a design goal that it should be possible to write generic algorithms that work on different types of containers, not all of which would be template specializations of the form C<T>. It then makes sense to mandate that all containers expose value_type because that's the only uniform way of extracting the element type from arbitrary containers.
If std::function were also an instance of some Callable concept, it would make sense to have the requirement that there is a function_type typedef so that code accepting any Callable could access the function type. But that's not the case, and it's not useful to have it for only the single template std::function.
You can easily write one:
template < typename T >
struct function_type;
template < typename Sig >
struct function_type<std::function<Sig>> { using type = Sig; };
On your terminology: instantiate is the word you're looking for. You are looking for the type that the template was instantiated with.
The only people who know why it isn't a member type are those who designed the feature and those who voted it in (maybe). It could simply be something nobody thought of. It does seem a bit obvious, but that's in hindsight from the perspective of wanting it.
Java and I guess C#(and others) support Bounded Type Parameters which lets us restrict what types may be used in template classes/functions.
I am curious if there is a reason, official or otherwise, for not adding native support for bounded types to C++? Anything to do with how templates are currently processed? Multiple inheritance issues?
I would expect it to be quite useful.
C++ has SFINAE which can be exploited via std::enable_if fairly easily. In conjunction with type_traits it is actually, IMO, more powerful than the bounded types that Java and C# have. With a little work you can also make some nice constexpr functions to test these things out for you. Combine that with some macros and you have something that looks sorta like it
#include <iostream>
#include <type_traits>
#define ENABLE_IF typename std::enable_if<
#define THEN(T) ,T>::type
class foo {};
class bar : public foo {};
template<class T, class U>
constexpr bool extends() {
return std::is_base_of<
typename std::remove_reference<U>::type,
typename std::remove_reference<T>::type
>::value;
}
template<class T>
ENABLE_IF extends<T, foo>() THEN(void) test(T&& v) {
std::cout << "T extends foo!!";
}
int main() {
test(bar{});
}
Now I'm not sure I would recommenced this but it is doable and as of now I see no issue in doing it beyond SFINAE being hard to debug
The simple fact is, the reason why this is not in is because nobody has come up with a feature that would make it work without horrific side effects. The Committee has been working on the problem for a decade or more, and the latest iteration still isn't fit for purpose.
Also, the generic restrictions you refer to are not bounded types at all. The only bound they support is "X inherits from Y", essentially, and frankly, SFINAE with std::is_base_of covers this situation just fine. C++ would need something far more powerful to be useful, since run-time inheritance is one of the least useful features.
Most of the time, the constraints on a template argument should not be on the type, but on the operations that the template needs. C++ does that, in a somewhat awkward way, simply because you get an error message if an operation that the template uses isn't there. For example:
template <class T>
void show(T t) {
std::cout << t << std::endl;
}
If you call this template function with a type that doesn't implement operator<< you'll get an error. The Java approach would be to define an interface with a print method, and require that the user pass an object of a type that implements that interface. The C++ approach doesn't require all that mechanism.
The problem with doing this in C++ is that you can get error messages that are very confusing. Often the missing operation is used in some low-level part of another template, and the error message has no clear relation to the code that you wrote. That's one of the drives behind concepts: the author of the template can set out what operations it uses, and passing an object whose type doesn't support those operations will result in a violation of the concept right at the interface, instead of deep within the implementation, so you will probably get a more useful error message.
The purpose of the bounded type parameter is to raise a compile-time error in case of a mismatch of the supplied type and a desired base-class, so this is easily achievable in C++11 and up, with a static_assert and supplying to it the value of the std::is_base_of as follows:
template <typename T>
class C {
static_assert(std::is_base_of<SomeBoundedBaseClass, T>::value, "Bounded type parameter violation!");
//...the rest of the class C
};
where SomeBoundedBaseClass is your class to which you want to bound the type parameter T to be a descendant of or match exactly.
Also note that this way you can mention any custom message to be shown as a compile error, so it has even an advantage over the Java's built-in functionality. Needless to say that C++ is more verbose, but it gives also more freedom.
Disclaimer: the question is completely different from Inheritance instead of typedef and I could not find any similar question so far
I like to play with c++ template meta-programming (at home mostly, I sometimes introduce it lightly at work but I don't want to the program to become only readable to anyone who did not bother learning about it), however I have been quite put out by the compiler errors whenever something goes wrong.
The problem is that of course c++ template meta-programming is based on template, and therefore anytime you get a compiler error within a deeply nested template structure, you've got to dig your way in a 10-lines error message. I have even taken the habit of copy/pasting the message in a text-editor and then indent the message to get some structure until I get an idea of what is actually happening, which adds some work to tracking the error itself.
As far as I know, the problem is mostly due to the compiler and how it output typedefs (there are other problems like the depth of nesting, but then it's not really the compiler fault). Cool features like variadic templates or type deduction (auto) are announced for the upcoming C++0x but I would really like to have better error messages to boot. It can prove painful to use template meta-programming, and I do wonder what this will become when more people actually get into them.
I have replaced some of the typedefs in my code, and use inheritance instead.
typedef partition<AnyType> MyArg;
struct MyArg2: partition<AnyType> {};
That's not much more characters to type, and this is not less readable in my opinion. In fact it might even be more readable, since it guarantees that the new type declared appears close to the left margin, instead of being at an undetermined offset to the right.
This however involves another problem. In order to make sure that I didn't do anything stupid, I often wrote my templates functions / classes like so:
template <class T> T& get(partition<T>&);
This way I was sure that it can only be invoked for a suitable object.
Especially when overloading operators such as operator+ you need some way to narrow down the scope of your operators, or run the risk of it been invoked for int's for example.
However, if this works with a typedef'ed type, since it is only an alias. It sure does not work with inheritance...
For functions, one can simply use the CRTP
template <class Derived, class T> partition;
template <class Derived, class T> T& get(partition<Derived,T>&);
This allows to know the 'real' type that was used to invoke the method before the compiler used the public inheritance. One should note that this decrease the chances this particular function has to be invoked since the compiler has to perform a transformation, but I never noticed any problem so far.
Another solution to this problem is adding a 'tag' property to my types, to distinguish them from one another, and then count on SFINAE.
struct partition_tag {};
template <class T> struct partition { typedef partition_tag tag; ... };
template <class T>
typename boost::enable_if<
boost::same_type<
typename T::tag,
partition_tag
>,
T&
>::type
get(T&)
{
...
}
It requires some more typing though, especially if one declares and defines the function / method at different places (and if I don't bother my interface is pretty soon jumbled). However when it comes to classes, since no transformation of types is performed, it does get more complicated:
template <class T>
class MyClass { /* stuff */ };
// Use of boost::enable_if
template <class T, class Enable = void>
class MyClass { /* empty */ };
template <class T>
class MyClass <
T,
boost::enable_if<
boost::same_type<
typename T::tag,
partition_tag
>
>
>
{
/* useful stuff here */
};
// OR use of the static assert
template <class T>
class MyClass
{
BOOST_STATIC_ASSERT((/*this comparison of tags...*/));
};
I tend to use more the 'static assert' that the 'enable_if', I think it is much more readable when I come back after some time.
Well, basically I have not made my mind yet and I am still experimenting between the different technics exposed here.
Do you use typedefs or inheritance ?
How do you restrict the scope of your methods / functions or otherwise control the type of the arguments provided to them (and for classes) ?
And of course, I'd like more that personal preferences if possible. If there is a sound reason to use a particular technic, I'd rather know about it!
EDIT:
I was browsing stackoverflow and just found this perl from Boost.MPL I had completely forgotten:
BOOST_MPL_ASSERT_MSG
The idea is that you give the macro 3 arguments:
The condition to check
a message (C++ identifier) that should be used for display in the error message
the list of types involved (as a tuple)
It may help considerably in both code self documentation and better error output.
What you are trying to do is to explicitly check whether types passed as template arguments provide the concepts necessary. Short of the concept feature, which was thrown out of C++0X (and thus being one of the main culprits for it becoming C++1X) it's certainly hard to do proper concept checking. Since the 90ies there have been several attempts to create concept-checking libraries without language support, but, basically, all these have achieved is to show that, in order to do it right, concepts need to become a feature of the core language, rather than a library-only feature.
I don't find your ideas of deriving instead of typedef and using enable_if very appealing. As you have said yourself, it often obscures the actual code only for the sake of better compiler error messages.
I find the static assert a lot better. It doesn't require changing the actual code, we all are used to having assertion checks in algorithms and learned to mentally skip over them if we want to understand the actual algorithms, it might produce better error messages, and it will carry over to C++1X better, which is going to have a static_assert (completely with class designer-provided error messages) built in into the language. (I suspect BOOST_STATIC_ASSERT to simply use the built-in static_assert if that's available.)