I want to have a template parameter accept a template that has a numeric template argument.
This example maybe overly simplified, but I'd like something like this:
template <int X>
struct XX
{
static const int x = X;
};
template<typename TT, TT V, template<V> TX>
void fnx(TX<V> x)
{
static_assert(V == TX::x, "IMPOSSIBLE!");
}
void fny()
{
fnx(XX<1>())
}
I must not be understanding the syntax for this, as it must be possible. How would I accomplish this?
Just fixing up your syntax a bit - since the template template parameter is improperly specified, we'd end up with something like this:
template <typename T, template <T > class Z, T Value>
// ^^^^^^^^^^^^^^^^^^^^^
void foo(Z<Value> x) { }
However, the compiler can't deduce T here - it's a non-deduced context. You'd have to explicitly provide it:
foo<int>(XX<1>{});
That's pretty annoying. I cannot even write a type trait such that non_type_t<XX<1>> is int (where that type trait does actual introspection on the type, not something that trivially returns int).
There is a proposal to improve this process (P0127) by amending the non-deduced context-ness of non-type template arguments.
Your declaration of fnx needs some work, and the type TT can't be deduced at the call site.
template<typename TT, TT V, template<TT> class TX>
void fnx(TX<V> x)
{
static_assert(V == TX<V>::x, "IMPOSSIBLE!");
}
void fny()
{
fnx<int>(XX<1>());
}
Working example: https://ideone.com/57PsCA
Related
Let's imagine I have some complicated templated function and I want to test that it works as expected.
In particular that when invoked with certain arguments that type of function is determined only by first argument.
For example:
template<typename T>
bool less(const T& x, const std::type_identity_t<T>& y){
return x < y;
}
Here I would like to check something (with static_assert or some test framework expect) that only first argument determines the signature of the function, something like:
std::is_same_v<decltype(less(short{1}, long{2})) , decltype(less(short{1}, double{2}))>;
But obviously this does not work since decltype will give me the result of function invocation, not the type of the function that is instantiated when I give it arguments I gave it.
Is there a way to do this(assume I can not modify the function, e.g. make it a functor with typedefed T or change it any other way)?
I tried searching for this, failed, I guess somebody asked this already but I could not find the question.
note: I know about testing behaviors, not implementation. Example is just tiny example, not something realistic.
This isn't a full answer, but something like this should_convert_to might work to test the less function:
#include <type_traits>
template <typename expected>
struct should_convert_to{
template <typename actual>
operator actual() {
static_assert(std::is_same_v<expected, actual>);
return {};
}
};
auto result = less(int{1}, should_convert_to<int>());
static_assert(std::is_same_v<decltype(result), bool>);
// error: static_assert failed due to requirement 'std::is_same_v<short, int>'
// less(int{1}, should_convert_to<short>());
You could use a wrapper class that gives you the signature:
// ...
template <typename, typename, typename = void>
struct less_fptr;
template <typename X, typename Y>
struct less_fptr<X, Y, std::enable_if_t<!std::is_convertible_v<Y, X>>> {
using type = less_fptr<X, Y>;
};
template <typename X, typename Y>
struct less_fptr<X, Y, std::enable_if_t<std::is_convertible_v<Y, X>>> {
using type = bool(*)(const X&, const std::type_identity_t<X>&);
};
// ...
static_assert(std::is_same_v<typename less_fptr<decltype(short{1}), decltype(long{2})>::type, typename less_fptr<decltype(short{1}), decltype(double{2})>::type>);
Let's say I have something, following the example on cppreference.com, but specified differently:
typedef double call_t(char, int&);
I need such a form of invocation of result_of that would give back the return type of the function signature defined as the above call_t. That is something that I could use as:
template <class Signature>
std::result_of<SOME_MAGIC_AROUND(Signature)>::type call(Signature* f)
{
return (*f)();
}
double d = call(fn); // where `fn` is declared as having `call_t` type
Doing result_of<call_t>::type doesn't work. I've tried also various combinations around it, but came to nothing.
You have to specify the parameters too. e.g.
template <class Signature>
typename std::result_of<Signature*(char, int&)>::type call(Signature* f)
// ^^^^^^^^^^^^^^^^^^^^^^
{
return (*f)(...);
}
LIVE
std::result_of has been deprecated since C++17, you can use std::invoke_result instead.
template <class Signature>
typename std::invoke_result<Signature*, char, int&>::type call(Signature* f)
// ^^^^^^^^^^^^^^^^^^^^^^
{
return (*f)(...);
}
EDIT
Signature is a template parameter, but expected to be a typedef for a function. I need its "return type" so that I can use as a return type for the call forwarder - regardless of what parameters a user might have specified for Signature.
You can make a type trait which gets the return type from the function type. e.g.
template <typename F>
struct return_type_of_function {};
template <typename R, typename... Args>
struct return_type_of_function<R(Args...)> {
using type = R;
};
then use it as
template <class Signature>
typename return_type_of_function<Signature>::type call(Signature* f)
{
return (*f)(...);
}
LIVE
In C++11 you can instantiate std::function like this:
std::function<void(int)> f1;
std::function<int(std::string, std::string)> f2;
//and so on
But while there is plenty of info on variadic templates on the web, I fail to find any articles on how to write std::function-like template which would accept parenthesized arguments.
Could anyone please explain the syntax and its limitations or at least point to an existing explanation?
There's nothing special about it, it's an ordinary function type. When you declare a function like this:
int foo(char a, double b)
Then its type is int (char, double). One way of "unwrapping" the individual argument types and return type is to use partial template specialisation. Basically, std::function looks something like this:
template <class T>
struct function; // not defined
template <class R, class... A>
struct function<R (A...)>
{
// definition here
};
Pretty much like any other template, since int(std::string, std::string) is just a type.
Here's a really naive example that compiles:
template <typename FType>
struct Functor
{
Functor(FType* fptr) : fptr(fptr) {}
template <typename ...Args>
void call(Args... args)
{
fptr(args...);
}
private:
FType* fptr;
};
void foo(int x, char y, bool z) {}
int main()
{
Functor<void(int, char, bool)> f(&foo);
f.call(1, 'a', true);
//f.call(); // error: too few arguments to function
}
In reality you'd have a specialisation on FType being ReturnType(ArgTypes...), though my naive example will already give you the validation you need if you try to invoke it in in compatible ways.
template<typename T>
Ref<Iterator<T> > GetFilterIterator(Ref<Iterator<T> > i, boost::function<bool(T)> pred) {
return new FilterIterator<T>(i, pred);
}
Ref<Iterator<CWorm*> > x = GetFilterIterator(worms(), &CWorm::getLocal);
And worms() returns a Ref<Iterator<CWorm*> Ref> and there is bool CWorm::getLocal(); (which is a member function). And:
template<typename T> struct Ref {
// ...
};
template<typename T> struct Iterator {
// ...
};
This will fail to deduce the template argument:
Iter.h:272:27: note: candidate template ignored: failed template argument deduction [3]
Why?
If I call it with the specified template argument, i.e. GetFilterIterator<CWorm*>(worms(), &CWorm::getLocal), it doesn't complain. I wonder why it cannot deduce the template argument like this. And can I make it different somehow so that it would be able to automatically deduce the type?
Do you mean typname Iterator<T>::Ref for the type of the first parameter in the GetFilterIterator template declaration? If so, that is not a deducible context for template type parameters.
Consider:
template<>
struct Iterator<Foo> {
typedef int Ref;
};
template<>
struct Iterator<Bar> {
typedef int Ref;
};
GetFilterIterator(int(0),f);
Both Iterator<Foo>::Ref and Iterator<Bar>::Ref match the parameter passed to GetFilterIterator, an int. Which one should it pick? C++ disallows deducing template types from parameters like the one you've declared.
With the update to your question it looks like you do mean ::Ref<Iterator<T> >. I think that should be deducible then, and since the typedef Iterator<CWorm*>::Ref is ::Ref<Iterator<CWorm*> > it seems like it should be able to deduce T. I'm not sure why it's not working.
The compiler cannot deduce the template arguments because fitting to the parameters would mean a non-trivial conversion - first to Iterator<T> and then to Ref<Iterator<T> > which both require user-defined conversions. Also, directly converting the member function pointer to boost::function is similarly non-trivial for the compiler.
IBM has a list of supported template parameter deductions.
If you want your template arguments to be deduced automatically, you have to provide wrapper methods:
template <typename T>
Ref<Iterator<T> > makeIteratorRef(T val) {
return Ref<Iterator<T> >(Iterator<T>(val));
}
template <typename T>
boost::function<bool (T)> makeFn(bool (T::*fn) () const) {
boost::function<bool (T)> res = boost::bind(fn, _1);
return res;
}
...
Ref<Iterator<CWorm*> > x = GetFilterIterator(makeIteratorRef(worms()), makeFn(&CWorm::getLocal));
This way the compiler is capable of deducing the template parameters because no conversions are necessary.
By the way, I think you are overcomplicating simple things:
for (auto it = worms().begin(); it != worms().end(); ++it)
if (it->isLocal()) {
// Do something
}
This code is way more readable in C++ and even though it might not be as general it hardly makes the code worse.
Thanks to the hint from Xeo to here about that implicit type conversions are not allowed when deducing template arguments, I wondered wether the second parameter might cause problems here. I thought that it would do the type deduction from left to right and once the type is deducted, it is not a problem anymore (for the function pointer to boost::function cast).
It seems I was wrong and this was exactly the problem.
Another version of the same thing avoids the problem:
template<typename T>
struct PartialFuncWrapper {
::Ref<Iterator<T> > i;
PartialFuncWrapper(::Ref<Iterator<T> > _i) : i(_i) {}
typename Iterator<T>::Ref operator()(boost::function<bool(T)> pred) {
return new FilterIterator<T>(i, pred);
}
};
template<typename T>
PartialFuncWrapper<T> GetFilterIterator(::Ref<Iterator<T> > i) {
return PartialFuncWrapper<T>(i);
}
Then I can write:
Ref<Iterator<CWorm*> > x = GetFilterIterator(worms())(&CWorm::getLocal);
Why can't the compiler figure out these template parameters? Is there a way to make it do so?
(I'm using Visual Studio 2010.)
template<typename T, typename TFunc>
void call(TFunc func) { func(T()); }
void myfunc(void *) { }
int main() { call(myfunc); }
T appears nowhere in the parameter list so T cannot be deduced from the function arguments. All types to be deduced must appear in deduced contexts in the parameter list. For example,
template <typename TReturn, typename TParameter>
void call(TReturn (*f)(TParameter))
{
f(TParameter());
}
Template parameter deduction for function templates only works based on function arguments, nothing else. The function definition is never looked at for the purpose of determining the template parameters, so your parameter T cannot possibly be deduced.
You could remedy your situation by incorporating the type into the function signature: Since you expect the outer function to be called with a function itself, make that explicit:
template <typename T> void foo(void(*f)(T))
{
T x;
f(x);
// ...
}
Combine function overloading with functors, and it becomes impossible in the general case to determine what arguments can be passed to a callable entity.
Consider, for example
struct FunctorExample {
void operator()(int x) {...}
std::string operator()(const std::string& ) {...}
};
If there were some way to coax the compiler to pattern match on arguments, it would have to have undefined or error behavior when applied to FunctorExample.
Instead, the trend seems to be that when you want to template metaprogram with functors, you specify the functor and argument list. Examples (off the top of my head) being boost::result_of and boost::fusion.
Edit: That said, if you're willing to restrict your attention somewhat, and you can use some C++11 syntax (decltype), you can arrange to introspect a bit more:
// Support functors with a very simple operator():
template <typename T> struct argument :
public argument<decltype(&T::operator())> {};
// Pointers to member functions
template <typename C, typename R, typename A> struct argument<R(C::*)(A)>
{typedef A type;};
// Function types
template <typename R, typename A> struct argument<R(A)> {typedef A type;};
// Function pointer types.
template <typename R, typename A> struct argument<R(*)(A)> {typedef A type;};
// Now for call:
template <typename FuncType>
void call(FuncType func) {
typedef typename argument<FuncType>::type Arg;
func(Arg());
}
// example:
class FunctorInt {public: int operator()(int ) {return 0;};};
void myfunc(void *) {}
int main() {
call(myfunc);
call(FunctorInt());
}
Variadic templates could be used to expand this stuff to support more than one argument.