I want to create the following types
using Function = std::function<Variant(int)>;
using Variant = std::variant<int, bool, Function>;
In Variant I need to have Function as well, but Function should return a Variant (by value). However I cannot find the right syntax. I was trying to forward-declare Function, but I'm not sure how to do this.
As far as I know, I should be able to write such a thing, because forward-declaration is usually enough regarding the return type of a function.
You can scaffold it, sure. You just cannot have both identifiers be aliases. An alias cannot be forward declared.
Something like this:
struct Variant;
using Function = std::function<Variant(int)>;
struct Variant : std::variant<int, bool, Function> {
using variant::variant;
};
Should work mostly as intended. The return type is incomplete initially (which should be okay so long as no operation is performed that requires it be complete). And then it's completed, by using the alias for Function.
The caveat is that Variant is now its own independent type. So some aspects of template argument deduction may work differently. But I doubt it's likely to rise up and bother you.
You also have the option of flipping the roles if needed. Be warned that the standard library may not be specified to behave reliably for types inheriting from its components. So some casting to a base class reference may be in order. Lay it out in the way that best works for you.
Related
I have an vector of std::type_index, which indicate the trait types that a particular node has. I'm implementing a function which checks whether the node supports a particular type. It looks like this:
std::vector<std::type_index> traits;
...
template <typename T>
bool hasTrait() {
return std::find(traits.begin(), traits.end(), typeid(T)) != traits.end();
}
However, this won't work if type T is a derived type of some base type in traits. In order to fix this problem, I wanted to use std::is_convertible.
However, I only have access to the std::type_index of the type, so I can't do that. Something like this would be required: std::is_convertible<traitTypeIndex::type, T>
At first I would mention that it is surely impossible with std::is_convertible. Like all other things from type_traits, std::is_convertibleis a purely compile-time thing. But you want it to give you answer during the run-time for some run-time argument (which is type_index).
The second question is if this check can be implemented at all for arbitrary polymorphic types (by "arbitrary" I mean that you don't have any specific design-time or run-time information). I think that it's not impossible because the whole run-time reflection we have in C++ is dynamic_cast (when RTTI is on). However, even in dynamic_cast we have one semi-dynamic argument (pointer or reference) and one static (type to which we wan't to convert). I write semi-dynamic because it needs to be a pointer or reference to some certain type, it cannot absolutely type-erased argument (like void*). I believe that to check dynamically if one of two types is the inheritor of the other one we need more support from a run-time.
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.
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.
I have a class that contains a private typedef and several member
functions:
class Foo
{
private:
typedef std::blahblah FooPart;
FooPart m_fooPart;
...
public:
int someFn1();
int someFn2();
};
Several member functions need to use m_fooPart in a similar way, so I
want to put that in a function. I put helper functions in the anonymous
namespace whenever I can, but in this case, they need to know what
FooPart is. So, I've done this:
namespace
{
template <typename T>
int helperFn(const T& foopart, int index)
{
...
return foopart.fn(index);
}
}
int Foo::someFn1()
{
...
return helperFn(m_fooPart, ix);
}
By forcing the compiler to produce the FooPart type, am I still in the
land of well-defined behavior? Is there a more elegant way of
accomplishing this that doesn't increase the size of Foo or make public
what is now private?
Yes, that approach produces well-defined, standards-compliant behavior.
That said, adding member functions to a class does not increase the size of a class (assuming you mean the result of the sizeof operator), so I'm not sure what drawback you perceive in just making the helper function a private member of Foo.
Simple answer: make the typedef public.
That will leak a minor detail of implementation (the actual internal type), but because it is typedefed you can redefine it at any time and it should be fine.
A little less simple: befriend the helper function, providing access to your internal type.
The problem with this second approach is that you are not only granting access to the typedef, but also to all the private parts of your class, and that might not be the best idea. At any rate, since this is an internal helper function, it is under your own control, and it should be fine. (Now that I think of it, you might want to declare the function in a named namespace, for the friend declaration to succeed)
Even less simple: Create a separate typedef inside the implementation file, and ensure that they are synchronized.
You can ensure that the types are the same with a small bit of metaprogramming, with a same_type<T,U> template that will provide a true value if the two types are the same and false otherwise. A static assert will trigger an error if the typedef changes in only one place
Back to simple again: provide the typedef or use the type directly without the static assert.
You are calling a function (this should not be a template as in your code) and passing a reference. If the typedef changes in the class, the call will fail and the compiler will tell you.
I would go for the last option, while it may look a little rough and less delicate than the others, the fact is that this is only an implementation detail that is not used by others, you are under full control of the code and well, simple is better.
EDIT, after the comment.
I started writing this as a comment, but it became too long, so I am adding it to the answer.
There is nothing wrong in that solution by itself, other than you are making a function generic unnecessarily and some error messages in the future might not be as simple as they could be with a non-generic signature. Note that the template will not expose the typedef (as the question title suggests) but rather it will make the compiler infer the type at the place of call.
If you change the typedef, instead of getting an error saying that the arguments to helperFn cannot be matched against the existing function, the type will be inferred and the function matched, but you will get an error deeper in helperFn if you use a property of the type that is no longer present. Or worse, you might not even get an error if it is the semantics of the type that have changed.
Consider that the typedef is of a std::list<X>, and that in the function you are iterating over it with this simple correct for loop:
for (typename T::iterator it=x.begin(), end=x.end(); it != end; ) {
if ( condition(*it) )
it = x.erase(it);
else
++it;
}
Can you catch the effect that changing the typedef to std::vector<X> will have? The compiler cannot even if the code is now incorrect. Whether writing the for loop like that is a good idea, or why is it not just using the erase-remove idiom are different issues (as a matter of fact the previous loop is arguably better than erase-remove for a list), the concrete situation is that the semantics have changed, and because the type is syntactically compatible with the previous one the compiler will not notice that the code is wrong, it will not point you to that function and chances are that you will not review/rewrite it.
I guess this is the idea of generic programming - do stuff with a part of Foo without knowing its type.
A more "traditional" (strongly-typed, boring, readable, code-duplicating - you name it) way would be to mention the type explicitly:
int helperFn(const std::blahblah& foopart, int index)
{
...
return foopart.fn(index);
}
Suppose I have the following code:
int f(int, int);
int main()
{
SomeFunc(boost::bind(f, 1, 2));
}
From the SomeFunc() function, is it possible to access the arguments held by the bound type? Something like this (pseudo code):
// Obvious syntax issues...
void SomeFunc(boost::bind& functor)
{
if(functor.function == &f)
{
if(functor.argument1 == 1)
DoSomething();
}
}
Can I pull this information out of the boost::bind type?
boost::bind is a templated function, not a type. The real type returned by that function is some kind of functor of an unspecified type. As a matter of fact, it probably returns many different unspecified types depending on what the arguments to the boost::bind function are.
As the type is unspecified and the library only states that is CopyConstructible, that implements operator() with the appropriate number and type of arguments (one for each placeholder, types deduced from the bound method/function) and that it offers an inner type result_type that is the same as the return type of that operator().
The interface of those unspecified classes is, well, unspecified. It will probably not offer accessors to the arguments, and even if it does, and you get inside knowledge from studying the internals of the library, you risk having your code break with upgrades to the library (the implementor is free to change the type and all the interface that is not publicly documented).
The whole library is built around the fact that you do not really care about what the arguments are or even if any argument is defined or only placeholders are used, you only care that the resulting object will be callable with a given interface.
So no, you cannot.
The real question is why would you want to do that?
I suspect you can't but the fact that you are trying is a bit worrying.
No, you cannot do that with boost::bind.
boost::bind just generates a sort of functor object where all details are hidden. Than you construct boost::function or boost::signal with it and the only thing you can do: execute. You even cannot compare boost::function objects.
Anyway, it is not clear that the problem you are solving. Such approach looks awkward to me. Are you sure you really need that?