N
Noah Roberts
So I am trying to come up with a way to do concepts in C++11. Mostly
they can be implemented with TMP and SFINAE using decltype. For
example:
template < typename T, typename R, typename ... Args >
struct can_call_fun<T,R(Args...)>
{
typedef char (&yes) [1];
typedef char (&no) [2];
template < typename U >
static yes check(decltype(declval<U>().fun(declval<Args>()...)) * );
template < typename U >
static no check(...);
enum { value = sizeof(check<T>(0)) == sizeof(yes) };
};
The above metafunction will establish that you can use the
t.fun(x,x,x) syntax on an instance of T. I'll use another check to
verify that you can convert the return to a specific target type. The
purpose of this construct above and beyond simply trying to grab a
member function pointer and checking types is that the target could be
realizing this concept with template functions or even functor
members. The naive member function check would fail under these
conditions even if the type really does realize the target concept.
This metafunction then is a step toward allowing these kinds of
realizations.
BUT...this metafunction succeeds if the types of args are convertible,
even if doing so is unsafe and would generate a warning under some
compile flags. If one used "-Wconversion -Werror" for example and
passed a type to this thing expecting it to say "NO" when you pass
doubles to a function expecting ints, you would be mistaken; on very
recent versions of g++ that is. The concept check would then succeed
and fail deep down inside the template instantiation, which is sort of
the point of doing concepts to begin with.
The fact that it succeeds when types are convertible is a good thing.
An object that has a function taking two ints and returning void
should probably match a concept that requires a function of the same
name but takes shorts instead because the preconditions are more
allowing than the concept requires. Also a function that takes the
appropriate arguments and then additionally some default arguments
should match. However, if the function takes shorts but the concept
requires ints then the match seems incorrect, but this metafunction
would claim it matches.
I've been struggling for a few days to consider a way to check that
coersion will not lose information. The return is easy since I can
get that from the decltype expression and write a metafunction that
uses a table to establish information loss. On the other hand, the
parameters is a problem for this construct. There are some things you
could maybe try, fail, and try another with, but when it comes to
templates and such it seems to me that it would be damn near
impossible to predict a signature and grab the address or whatever.
So.... any ideas?
they can be implemented with TMP and SFINAE using decltype. For
example:
template < typename T, typename R, typename ... Args >
struct can_call_fun<T,R(Args...)>
{
typedef char (&yes) [1];
typedef char (&no) [2];
template < typename U >
static yes check(decltype(declval<U>().fun(declval<Args>()...)) * );
template < typename U >
static no check(...);
enum { value = sizeof(check<T>(0)) == sizeof(yes) };
};
The above metafunction will establish that you can use the
t.fun(x,x,x) syntax on an instance of T. I'll use another check to
verify that you can convert the return to a specific target type. The
purpose of this construct above and beyond simply trying to grab a
member function pointer and checking types is that the target could be
realizing this concept with template functions or even functor
members. The naive member function check would fail under these
conditions even if the type really does realize the target concept.
This metafunction then is a step toward allowing these kinds of
realizations.
BUT...this metafunction succeeds if the types of args are convertible,
even if doing so is unsafe and would generate a warning under some
compile flags. If one used "-Wconversion -Werror" for example and
passed a type to this thing expecting it to say "NO" when you pass
doubles to a function expecting ints, you would be mistaken; on very
recent versions of g++ that is. The concept check would then succeed
and fail deep down inside the template instantiation, which is sort of
the point of doing concepts to begin with.
The fact that it succeeds when types are convertible is a good thing.
An object that has a function taking two ints and returning void
should probably match a concept that requires a function of the same
name but takes shorts instead because the preconditions are more
allowing than the concept requires. Also a function that takes the
appropriate arguments and then additionally some default arguments
should match. However, if the function takes shorts but the concept
requires ints then the match seems incorrect, but this metafunction
would claim it matches.
I've been struggling for a few days to consider a way to check that
coersion will not lose information. The return is easy since I can
get that from the decltype expression and write a metafunction that
uses a table to establish information loss. On the other hand, the
parameters is a problem for this construct. There are some things you
could maybe try, fail, and try another with, but when it comes to
templates and such it seems to me that it would be damn near
impossible to predict a signature and grab the address or whatever.
So.... any ideas?