I have a set of structure's class as such:
template<typename T>
struct Foo {
T x_;
T y_;
constexpr Foo(T x, T y) : x_{x}, y_{y} {}
};
template<typename T, typename U, template<U> class Func>
class Bar {
private:
Foo<T> foo_;
Func<U> func_
size_t n_;
public:
Bar(Foo<T> foo, size_t n, Func<U> func) :
foo_{foo},
n_{n},
func_{func}
{}
};
And I'm trying to create a deduction guide for this class template...
// Doesn't compile
template<typename T, typename U, template<U> class Func>
Bar(Foo<T>, U, Func<U>)->
Bar<T,U,Func>;
// Doesn't compile
template<typename T, typename U, template<U> class Func>
Bar(Foo<T>, U, Func)->
Bar<T,U,Func>;
I'm not sure of the proper syntax for this when the template argument happens to be a template itself where that templated argument will be a function pointer, function object, functor, or a lambda that the class will store.
When I try to use U within Func<> it states "type name is not allowed" and if I remove it to be just Func without any template arguments, it states, "argument list for template template parameter 'Func' is missing"...
My intended use of Bar looks like this:
template<typename T>
constexpr T funcA(T x) {
return x;
}
template<typename T>
constexpr T funcB(T x) {
return x*x;
}
int main() {
Bar bar1{Foo{1.0, 3.0}, 1000, funcA<double>};
Bar bar2{Foo{3.7, 4.0}, 500, funcB<float>};
return 0;
}
EDIT - This section is intended for user: piotr-skotnicki
Note: The above was a pseudo code with the same signatures as a representation of my classes... Now that I have access to my IDE again, here is the "real" source.
Integrator.h
#pragma once
//#include <type_traits>
template <typename Field>
struct Limits {
Field lower;
Field upper;
constexpr Limits(Field a = 0, Field b = 0) :
lower{ a < b ? a : b },
upper{ a < b ? b : a }
{}
};
template <typename LimitType, typename Func>
class Integrator {
//static_assert(std::is_invocable_v<Func&>, "Invalid callable");
private:
Limits<LimitType> limits_;
size_t step_size_;
Func integrand_;
public:
Integrator(Limits<LimitType> limits, size_t stepSize, Func integrand) :
limits_{ limits },
step_size_{ stepSize },
integrand_{ integrand }
{}
constexpr auto evaluate() {
auto distance = limits_.upper - limits_.lower;
auto dx = distance / step_size_;
return calculate(dx);
}
private:
template<typename ValueType>
constexpr auto calculate(ValueType dx) {
ValueType result = 0.0;
for (size_t i = 0; i < step_size_; ++i) {
auto dy = integrand_(limits_.lower + i * dx);
auto area = dy * dx;
result += area;
}
return result;
}
};
//template <typename LimitType, typename Func>
//Integrator(Limits<LimitType>, size_t, Func)
//->Integrator<LimitType, Func>;
main.cpp
#include <iostream>
#include <exception>
#include "Integrator.h"
double funcE(double x) {
return x;
}
template <typename T>
constexpr T funcA_t(T x) {
return x;
}
// This Works!
int main() {
try {
std::cout << "Integration of f(x) = x from a=3.0 to b=5.0\nwith an expected output of 8\n";
Integrator integratorA{ Limits{3.0, 5.0}, 10000, funcA };
std::cout << integratorA.evaluate() << '\n';
}
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
// This was failing to compile... but now seems to work for some reason...
int main() {
try {
std::cout << "Integration of f(x) = x from a=3.0 to b=5.0\nwith an expected output of 8\n";
Integrator integratorA{ Limits{3.0, 5.0}, 10000, funcA_t<double> };
std::cout << integratorA.evaluate() << '\n';
}
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
// Same as above...
Integrator integrator{ Limits{3.0, 5.0}, 10000, &funcA_t<double> };
// wasn't compiling...
Beforehand Visual Studio was complaining that it couldn't deduce template argument Func... and I don't know why...
I don't know what was going on... maybe Visual Studio was acting up... It appears to be working now... very odd...
First of all, the below syntax:
template <typename T, typename U, template <U> class Func>
doesn't mean that Func will have a single type template argument, the same as the second template argument U of a Bar instance itself.
It means that Func is a class template that takes a non-type template parameter of type U. If Func requires a type template parameter, that should become:
template <typename T, typename U, template <typename> class Func>
// ~~~~~~~^
And a matching deduction guide:
template <typename T, typename U, template <typename> class Func>
Bar(Foo<T>, U, Func<U>) -> Bar<T, U, Func>;
However, Func remains a template template parameter, and accepts only alias/class/struct templates, and that will never match a function pointer type, nor a lambda expression. If you indend to store any callable object inside Bar instances, then use any type as a template parameter, and let the deduction guide deduce which is it:
template <typename T, typename U, typename Func>
// ~~~~~~~^
In order to make sure that it will be callable with an (lvalue) argument of type U, just put a constraint like a static_assert:
#include <type_traits>
template <typename T, typename U, typename Func>
class Bar {
static_assert(std::is_invocable_v<Func&, U&>, "Invalid callable");
private:
Foo<T> foo_;
Func func_;
U n_;
public:
Bar(Foo<T> foo, U n, Func func) :
foo_{foo},
func_{func},
n_{n}
{}
};
DEMO
Also note that you don't need an explicit deduction guide, as one will be generated implicitly from the constructor.
However, if you don't know in advance what U will be used as an argument to Func, then that shouldn't be considered as a problem in the constructor definition, nor in the class definition itself. It's a clear indication that the argument will be supplied from some external source, and at some place you will know and will be able to verify whether it fits the callable or not.
For sure, you should not be trying to deduce the exact signature of a callable object. It's useless in practice and most probably means there's a flaw in your design.
That is, once you eventually know what type of an argument is used, put a static_assert there, e.g.:
template <typename ValueType>
constexpr auto calculate(ValueType dx) {
static_assert(std::is_invocable_v<Func&, ValueType&>, "Invalid value type");
ValueType result = 0.0;
// ...
return result;
}
Alternatively, you can make calculate SFINAE-friendly with std::enable_if_t or requires:
template <typename ValueType>
constexpr auto calculate(ValueType dx)
-> std::enable_if_t<std::is_invocable_v<Func&, ValueType&>, ValueType> {
ValueType result = 0.0;
// ...
return result;
}
Related
What I'm trying to do is find a clean way to implement a concept for a callable object that takes in a single parameter of type either int or long.
My first attempt was to create a single concept with a secondary template parameter to ensure the parameter type is either int or long. The problem with this approach, as seen in the example below, is that applications of this concept can't infer template parameters. For example, the usages of call() below require that template parameters be explicitly listed out.
// https://godbolt.org/z/E519s8Pso
//
#include <concepts>
#include <iostream>
// Concept for a callable that can take a single parameter or either int or long.
template<typename T, typename P>
concept MySpecialFunction =
(std::same_as<P, int> || std::same_as<P, long>)
&& requires(T t, P l) {
{ t(l) } -> std::same_as<decltype(l)>;
};
// T must be callable with 1 parameter that is either int or long!
template<typename T, typename P>
requires MySpecialFunction<T, P>
decltype(auto) call(T t) {
return t(2);
}
// Test
int square_int(int num) {
return num * num;
}
long square_long(long num) {
return num * num;
}
int main() {
std::cout << call<decltype(square_int), int>(square_int) << std::endl;
std::cout << call<decltype(square_long), long>(square_long) << std::endl;
return 0;
}
My second attempt was to explode out the concept to one for int and one for long, then combine them together in a third concept. In this version, the usages of call() below don't require that template parameters be explicitly listed out, but the concept is more verbose. Imagine how something like this would look if there were more than 20 types instead of just 2.
// https://godbolt.org/z/hchT11rMx
//
#include <concepts>
#include <iostream>
// Concept for a callable that can take a single parameter or either int or long.
template<typename T>
concept MySpecialFunction1 = requires(T t, int i) {
{ t(i) } -> std::same_as<decltype(i)>;
};
template<typename T>
concept MySpecialFunction2 = requires(T t, long l) {
{ t(l) } -> std::same_as<decltype(l)>;
};
template<typename T>
concept MySpecialFunction = MySpecialFunction1<T> || MySpecialFunction2<T>;
// T must be callable with 1 parameter that is either int or long!
template<MySpecialFunction T>
decltype(auto) call(T t) {
return t(2);
}
// Test
int square_int(int num) {
return num * num;
}
long square_long(long num) {
return num * num;
}
int main() {
std::cout << call(square_int) << std::endl;
std::cout << call(square_long) << std::endl;
return 0;
}
Is there anyway to have the conciseness / easy of understanding that the first example gives without the compiler losing the ability to infer template parameters as happens in the second example?
Since you have the types int and long baked into the concept, why don't you use something like this:
//true if Fn accepts one parameter (int or long) and have the same type as the result
template <typename Fn>
concept MySpecialFunction = requires (Fn fn) {
requires
std::same_as<int, decltype(fn(0))> ||
std::same_as<long, decltype(fn(0L))>;
};
template <MySpecialFunction Fn>
decltype(auto) call(Fn fn)
{
//think about what happens if Fn is square_long
//doesn't the type of the value (int) gets converted to long?
//that raises the question what your main purpose is
return fn(2);
}
See: https://godbolt.org/z/Y7vTrPoP5
Maybe you also want to have a look at:
https://en.cppreference.com/w/cpp/concepts/invocable
https://en.cppreference.com/w/cpp/utility/functional/invoke
After some browsing around, I came across https://stackoverflow.com/a/43526780/1196226 and https://stackoverflow.com/a/22632571/1196226. I was able to utilize these answers to build out a solution that can apply concepts to parameters concisely and without the compiler losing the ability to infer template parameters.
// https://godbolt.org/z/nh8nWxhzK
//
#include <concepts>
#include <iostream>
template <std::size_t N, typename T0, typename ... Ts>
struct typeN { using type = typename typeN<N-1U, Ts...>::type; };
template <typename T0, typename ... Ts>
struct typeN<0U, T0, Ts...> { using type = T0; };
template <std::size_t, typename F>
struct argN;
template <std::size_t N, typename R, typename ... As>
struct argN<N, R(*)(As...)> { using type = typename typeN<N, As...>::type; }; // needed for std::integral<>
template <std::size_t N, typename R, typename ... As>
struct argN<N, R(As...)> { using type = typename typeN<N, As...>::type; }; // needed for std::is_integeral_v<>
template <typename F>
struct returnType;
template <typename R, typename ... As>
struct returnType<R(*)(As...)> { using type = R; }; // works for std::integral<> / std::same_as<>
template <typename R, typename ... As>
struct returnType<R(As...)> { using type = R; }; // needed for std::is_integeral_v<>
template<typename Fn>
concept MySpecialFunction =
(std::same_as<typename argN<0U, Fn>::type, int> || std::same_as<typename argN<0U, Fn>::type, long>)
&& std::same_as<typename returnType<Fn>::type, typename argN<0U, Fn>::type>;
template<MySpecialFunction Fn>
decltype(auto) call(Fn fn) {
return fn(2);
}
// Test
int square_int(int num) {
return num * num;
}
long square_long(long num) {
return num * num;
}
static_assert( std::is_integral_v<typename argN<0U, decltype(square_int)>::type> );
static_assert( std::is_integral_v<typename returnType<decltype(square_int)>::type> );
static_assert( std::is_integral_v<typename argN<0U, decltype(square_long)>::type> );
static_assert( std::is_integral_v<typename returnType<decltype(square_long)>::type> );
int main() {
std::cout << call(square_int) << std::endl;
std::cout << call(square_long) << std::endl;
return 0;
}
I have this code:
template<class T1, class T2>
class Pair
{
private:
T1 first;
T2 second;
public:
void SetFirst(T1 first)
{
this.first = first;
}
void SetSecond(T2 second)
{
this.second = second;
}
T1 GetFirst()
{
return first;
}
T2 GetSecond()
{
return second;
}
};
How could I implement two single methods SetValue() and GetValue(), instead of the four I have, that decides depending on parameters which generic type that should be used? For instance I'm thinking the GetValue() method could take an int parameter of either 1 or 2 and depending on the number, return either a variable of type T1 or T2. But I don't know the return type beforehand so is there anyway to solve this?
Not sure to understand what do you want and not exactly what you asked but...
I propose the use of a wrapper base class defined as follows
template <typename T>
class wrap
{
private:
T elem;
public:
void set (T const & t)
{ elem = t; }
T get () const
{ return elem; }
};
Now your class can be defined as
template <typename T1, typename T2>
struct Pair : wrap<T1>, wrap<T2>
{
template <typename T>
void set (T const & t)
{ wrap<T>::set(t); }
template <typename T>
T get () const
{ return wrap<T>::get(); }
};
or, if you can use C++11 and variadic templates and if you define a type traits getType to get the Nth type of a list,
template <std::size_t I, typename, typename ... Ts>
struct getType
{ using type = typename getType<I-1U, Ts...>::type; };
template <typename T, typename ... Ts>
struct getType<0U, T, Ts...>
{ using type = T; };
you can define Pair in a more flexible way as follows
template <typename ... Ts>
struct Pair : wrap<Ts>...
{
template <typename T>
void set (T const & t)
{ wrap<T>::set(t); }
template <std::size_t N, typename T>
void set (T const & t)
{ wrap<typename getType<N, Ts...>::type>::set(t); }
template <typename T>
T get () const
{ return wrap<T>::get(); }
template <std::size_t N>
typename getType<N, Ts...>::type get ()
{ return wrap<typename getType<N, Ts...>::type>::get(); }
};
Now the argument of set() can select the correct base class and the correct base element
Pair<int, long> p;
p.set(0); // set the int elem
p.set(1L); // set the long elem
otherwise, via index, you can write
p.set<0U>(3); // set the 1st (int) elem
p.set<1U>(4); // set the 2nd (long) elem
Unfortunately, the get() doesn't receive an argument, so the type have to be explicited (via type or via index)
p.get<int>(); // get the int elem value
p.get<long>(); // get the long elem value
p.get<0U>(); // get the 1st (int) elem value
p.get<1U>(); // get the 2nd (long) elem value
Obviously, this didn't work when T1 is equal to T2
The following is a (C++11) full working example
#include <iostream>
template <std::size_t I, typename, typename ... Ts>
struct getType
{ using type = typename getType<I-1U, Ts...>::type; };
template <typename T, typename ... Ts>
struct getType<0U, T, Ts...>
{ using type = T; };
template <typename T>
class wrap
{
private:
T elem;
public:
void set (T const & t)
{ elem = t; }
T get () const
{ return elem; }
};
template <typename ... Ts>
struct Pair : wrap<Ts>...
{
template <typename T>
void set (T const & t)
{ wrap<T>::set(t); }
template <std::size_t N, typename T>
void set (T const & t)
{ wrap<typename getType<N, Ts...>::type>::set(t); }
template <typename T>
T get () const
{ return wrap<T>::get(); }
template <std::size_t N>
typename getType<N, Ts...>::type get ()
{ return wrap<typename getType<N, Ts...>::type>::get(); }
};
int main()
{
//Pair<int, int> p; compilation error
Pair<int, long, long long> p;
p.set(0);
p.set(1L);
p.set(2LL);
std::cout << p.get<int>() << std::endl; // print 0
std::cout << p.get<long>() << std::endl; // print 1
std::cout << p.get<long long>() << std::endl; // print 2
p.set<0U>(3);
p.set<1U>(4);
p.set<2U>(5);
std::cout << p.get<0U>() << std::endl; // print 3
std::cout << p.get<1U>() << std::endl; // print 4
std::cout << p.get<2U>() << std::endl; // print 5
}
C++ is statically typed, so the argument given must be a template-argument instead a function-argument.
And while it will look like just one function each to the user, it's really two.
template <int i = 1> auto GetValue() -> std::enable_if_t<i == 1, T1> { return first; }
template <int i = 2> auto GetValue() -> std::enable_if_t<i == 2, T2> { return second; }
template <int i = 1> auto SetValue(T1 x) -> std::enable_if_t<i == 1> { first = x; }
template <int i = 2> auto SetValue(T2 x) -> std::enable_if_t<i == 2> { second = x; }
I use SFINAE on the return-type to remove the function from consideration unless the template-argument is right.
For this particular situation, you should definitely prefer std::pair or std::tuple.
You can simply overload SetValue() (provided T1 and T2 can be distinguished, if not you have a compile error):
void SetValue(T1 x)
{ first=x; }
void SetValue(T2 x)
{ second=x; }
Then, the compiler with find the best match for any call, i.e.
Pair<int,double> p;
p.SetValue(0); // sets p.first
p.SetValue(0.0); // sets p.second
With GetValue(), the information of which element you want to retrieve cannot be inferred from something like p.GetValue(), so you must provide it somehow. There are several options, such as
template<typename T>
std::enable_if_t<std::is_same<T,T1>,T>
GetValue() const
{ return first; }
template<typename T>
std::enable_if_t<std::is_same<T,T2>,T>
GetValue() const
{ return second; }
to be used like
auto a = p.GetValue<int>();
auto b = p.GetValue<double>();
but your initial version is good enough.
So I was looking at the stl, and it seems like, for example, in std::transform, arguments that are function objects are just template parameters so that what exactly happens when the passed function object is called depends on what is passed:
template <class UnaryFunc>
void call(UnaryFunc f, int c)
{ std::cout << f(c)+c << std::endl;}
int a(int i) { return i; }
struct { int operator()(int i){return i;}} b;
int main()
{
call(a,2); //function call
call(b,2); //operator() method of b call
return 0;
}
This is great because it is very generic: it allows you to use stuff like boost::bind() and pass both functors (like b) and functions (like a) to the same function call.
However, this is too lenient. For example, passing a function with the signature int (int i, int j) would cause no errors until the call in call. If call were more complicated, this could lead to confusing errors that are hard to parse. I think this would all be avoided if there were a way to force the caller to only pass functors and functions with a certain signature. Is this possible?
First attempt
Short of Concepts, the best method we have currently is to observe the traits of a function and perform static_asserts on them. For example,
#include <iostream>
#include <functional>
#include <type_traits>
/**
* Function traits helpers.
**/
template <typename>
struct fail : std::integral_constant<bool, false> {};
template <typename ReturnType, std::size_t Arity>
struct alias {
static constexpr std::size_t arity = Arity;
using return_type = ReturnType;
}; // alias
/**
* A few useful traits about functions.
**/
template <typename T, typename Enable = void>
struct function_traits {
static_assert(fail<T>::value, "not a function.");
}; // function_traits
/* Top-level functions. */
template <typename R, typename... Args>
struct function_traits<R (*)(Args...)> : alias<R, sizeof...(Args)> {};
/* Const member functions. */
template <typename R, typename Class, typename ...Args>
struct function_traits<R (Class::*)(Args...) const> : alias<R, sizeof...(Args)> {};
/* Non-const member functions. */
template <typename R, typename Class, typename ...Args>
struct function_traits<R (Class::*)(Args...)> : alias<R, sizeof...(Args)> {};
/* operator() overloads. */
template <typename T>
struct function_traits<T, std::enable_if_t<std::is_class<T>::value>>
: function_traits<decltype(&T::operator())> {};
/* std::function. */
template <typename R, typename ...Args>
struct function_traits<std::function<R (Args...)>> : alias<R, sizeof...(Args)> {};
/**
* Example contraints on UnaryFunc.
**/
template <typename UnaryFunc, typename Arg>
void call(UnaryFunc f, Arg arg) {
static_assert(function_traits<UnaryFunc>::arity == 1,
"UnaryFunc must take one parameter.");
static_assert(
std::is_integral<typename function_traits<UnaryFunc>::return_type>::value,
"UnaryFunc must return an integral.");
std::cout << f(arg) + arg << std::endl;
}
int a(int i) { return i; }
struct {
int operator()(int i){ return i; }
} b;
int c(int i, int j) { return i + j; }
std::string d(int) { return ""; }
int main() {
call(a, 2); // function call
call(b, 2); // operator() method of b call
// call(1, 2); // static_assert: "not a function".
// call(c, 2); // static_assert: "UnaryFunc must take one parameter".
// call(d, 2); // static_assert: "UnaryFunc must return an integral".
}
Second attempt
This attempt addresses limitations of the first approach, which mainly is the fact that the unary_fn couldn't be overloaded. It also adds a more restricted test where the result of f(arg) and arg can be added.
Note: C++14 version of std::result_of_t is required here, since the C++11 version doesn't give SFINAE behavior.
#include <iostream>
#include <type_traits>
/**
* Useful utilities
**/
template <typename...>
struct success : std::true_type {};
template <typename...>
struct fail : std::false_type {};
/**
* 'is_addable' type_trait.
* Takes two types and tests if they can be added together.
**/
template <typename Lhs, typename Rhs>
success<decltype(std::declval<Lhs>() + std::declval<Rhs>())>
is_addable_impl(void *);
template <typename Lhs, typename Rhs>
std::false_type is_addable_impl(...);
template <typename Lhs, typename Rhs>
struct is_addable : decltype(is_addable_impl<Lhs, Rhs>(nullptr)) {};
/**
* 'call' implementation.
* If the result of unary_fn(arg) can be added to arg, dispatch to the first
* overload, otherwise provide a static asertion failure.
**/
template <typename UnaryFn, typename Arg>
std::enable_if_t<is_addable<std::result_of_t<UnaryFn (Arg)>, Arg>::value,
void> call_impl(UnaryFn unary_fn, Arg arg, void *) {
std::cout << unary_fn(arg) + arg << std::endl;
}
template <typename UnaryFn, typename Arg>
void call_impl(UnaryFn unary_fn, Arg arg, ...) {
static_assert(fail<UnaryFn, Arg>::value,
"UnaryFn must be a function which takes exactly one argument "
"of type Arg and returns a type that can be added to Arg.");
}
template <typename UnaryFn, typename Arg>
void call(UnaryFn unary_fn, Arg arg) {
return call_impl(unary_fn, arg, nullptr);
}
/**
* Tests.
**/
int a(int i) { return i; }
struct {
int operator()(int i){ return i; }
std::string operator()(std::string s){ return s; }
} b;
int c(int i, int j) { return i + j; }
std::string d(int) { return ""; }
int main() {
call(a, 2); // function call
call(b, 2); // operator() method of b call
call(b, "hello"); // operator() method of b call
// call(1, 2); // static_assert fail
// call(c, 2); // static_assert fail
// call(d, 2); // static_assert fail
}
Third attempt (Thanks #dyp for the suggestion)
EDIT: By adding the operator<< calls into the decltype, we get an additional test that that the result of unary_fn(arg) + arg is also printable.
If is_addable is a useful type trait, it can be factored out as per the second attempt.
If not, however we can simply perform SFINAE inline in decltype. Even shorter and cleaner.
#include <iostream>
#include <type_traits>
template <typename...>
struct fail : std::false_type {};
/**
* 'call' implementation.
* If the result of unary_fn(arg) can be added to arg, dispatch to the
* first overload, otherwise provide a static asertion failure.
**/
template <typename UnaryFn, typename Arg>
auto call_impl(UnaryFn unary_fn, Arg arg, void *)
-> decltype(std::cout << unary_fn(arg) + arg << std::endl, void()) {
std::cout << unary_fn(arg) + arg << std::endl;
}
template <typename UnaryFn, typename Arg>
void call_impl(UnaryFn unary_fn, Arg arg, ...) {
static_assert(fail<UnaryFn, Arg>::value,
"UnaryFn must be a function which takes exactly one argument "
"of type Arg and returns a type that can be added to Arg.");
}
template <typename UnaryFn, typename Arg>
void call(UnaryFn unary_fn, Arg arg) {
call_impl(unary_fn, arg, nullptr);
}
/**
* Tests.
**/
int a(int i) { return i; }
struct {
int operator()(int i){ return i; }
std::string operator()(std::string s){ return s; }
} b;
int c(int i, int j) { return i + j; }
std::string d(int) { return ""; }
int main() {
call(a, 2); // function call
call(b, 2); // operator() method of b call
call(b, "hello"); // operator() method of b call
// call(1, 2); // static_assert fail
// call(c, 2); // static_assert fail
// call(d, 2); // static_assert fail
}
Um, I have an idea. (It requires C++11 at least.)
struct FunctorBase
{
virtual int operator ()(int i) = 0;
};
template <class UnaryFunc>
void call(UnaryFunc f, int c)
{
std::cout << f(c)+c << std::endl;
}
struct SomeFunctor final : public FunctorBase
{
virtual int operator ()(int i) override { ... }
};
int main()
{
call(SomeFunctor(), 3);
}
SomeFunctor::operator () is virtual, but SomeFunctor is final. So, if compiler knows its type in compile time, Calling operator () can be optimized by static-binding call. (And compiler knows the type when it specialize template <> void call(SomeFunctor, int), of course.)
And call still uses template to receive functor parameter, so it can still receive functors which don't inherit FunctorBase. (e.g. std::bind, ...)
Of course, SomeFunctor has an unnecessary vptr, and it can be unnecessary overhead. However it's just little overhead of sizeof(void *) - it can be ignored unless you require high-level optimizing.
(And There is the fact that types cannot have a zero size in most case, even if it is empty. So I guess it's not overhead.)
Moreover, if you mind it, the overhead can be reduced:
struct FunctorBase
{
#ifndef CHECK_FUNCTOR
virtual int operator ()(int i) = 0;
#endif
};
template <class UnaryFunc>
void call(UnaryFunc f, int c)
{
std::cout << f(c)+c << std::endl;
}
struct SomeFunctor final : public FunctorBase
{
int operator ()(int i) { ... }
};
int main()
{
call(SomeFunctor(), 3);
}
As you know, if the function of base class is virtual, the function of derived class becomes virtual, even if it doesn't declared virtual. It's a trick by using it >o<
Say I have the following code:
#include <iostream>
#include <functional>
template <int func(int)>
struct S : std::unary_function<int, int>
{
int operator()(int x) const
{
return func(x);
}
};
int foo(int x)
{
return x;
}
int main()
{
S<foo> s;
std::cout << s(42) << std::endl;
}
This works okay as a way of wrapping up a function inside of a functor, which means it can be used in other templated functions (like sort, for example (assuming the functor had the right signature)). I don't want to create a functor struct for every possible return/argument type (and realistically I can't), and so I tried the following:
template <template <typename R, // Make the return type and argument type template parameters!
typename A> R func(A)>
struct S : std::unary_function<R, A>
{
R operator()(A arg) const
{
return func(arg);
}
};
That didn't work; it gave me compilation errors. So then I tried:
template <typename R, typename A, R func(A)>
struct S : std::unary_function<R, A>
{
R operator()(A arg) const
{
return func(arg);
}
};
Which did work. Unfortunately though, I had to change instantiations of S to be S<int, int, foo> s; instead of the nicer S<foo> s;.
Is it at all possible to templatize the function passed as a template argument such that I can do S<foo> s; and not hard code the return type and argument type of the function in S?
My google-foo hasn't been able to find a specific answer.
Edit: Now I'm wondering if this isn't possible. I just thought of "what if foo is an overloaded function?" There wouldn't be, as far as I know, a way to know which foo to use when saying S<foo> s; and thus explicitly stating return/argument type is necessary. Is this correct thinking, and does this mean that the answer to my first question is "No, it's not possible"?
Unfortunately, I think it's the only way to prevent necessary conversions for passing functions.
But you can add function templates to help you deduce the types of (1) function args (2) function returns, like codes below:
template < typename R, typename A >
R result_of( R(A) );
template < typename R, typename A >
A arg0_of( R(A) );
Then you can use them to construct wanted function objects and let compilers do possible optimizations:
#define get_call( f ) call_t< decltype(result_of(f)), \
decltype(arg0_of(f)), f >()
// same as the class 'S'
template < typename R, typename A,
R unary( A ) >
struct call_t : std::unary_function<A,R> {
R operator()( A arg ) const {
return unary( arg );
}
};
Use the utility:
int neg( int arg ) {
return -arg;
}
auto s = get_call( neg );
cout << s( 1 ) << endl; // outputs: -1
It works too on function templates. Of course, you have to pass argument(s) to the template:
template < typename T >
T square( T arg ) {
return arg * arg;
}
template <>
int square( int arg ) {
cout << "square<int>()" << endl;
return arg * arg;
}
auto sq = get_call( square<int> );
cout << sq( 12 ) << endl; // outputs: square<int>()
// 144
Edit: for overloaded functions, you can do conversions to tell compilers which version you wanna invoke:
int cube( int arg ) {
return arg * arg * arg;
}
float cube( float arg ) {
return arg * arg * arg;
}
typedef float (*chosen)( float );
auto cu = get_call( (chosen)cube );
cout << showpoint << cu( 4 ) << endl; // outputs: 64.0000
You seem to want to have a non-type template template parameter. However, the only legal syntax for template template parameters is template < template-parameters > class. ("A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression." ยง 14.3.3)
You could create a templated class whose constructor argument was a function pointer, but I'm guessing that you're worried that will create an indirect function call.
That is not possible. It is the same problem in principle as the following one: you wish to write just A<100> where A is defined as:
template<T N>
struct A {};
Given N is 100, T turns out to be int. Fine. That is deducible by human mind, but not by the compilers even if they be 100% conformant to the C++11 Standard. I've exactly the same problem here:
Pretty-print types and class template along with all its template arguments
--
So the alternative solution I think is this:
template <typename R, typename A>
struct S : std::unary_function<R, A>
{
typedef R (*Fun)(A);
Fun func;
S(Fun f) : func(f) {}
R operator()(A arg) const
{
return func(arg);
}
};
And then define MakeS function as:
template<typename R, typename A>
S<R,A> MakeS(R (*fun)(A))
{
return S<R,A>(fun);
}
Which you can use it as:
auto s = MakeS(foo);
Or, simply this:
S<int,int> s(foo);
The downside with this alternative is that the function foo doesn't have any chance to be inlined now.
Does this work for you?
It may not be as nice as S<foo> but keeps the arguments as 1 at the point of instantiation.
int f(int) { return 0; }
template<class R, class A> struct S
{
typedef R(*FTYPE)(A);
typedef R RET;
typedef A ARG;
};
template<class R, class A> S<R, A> FW(R(f)(A));
template<class T> struct F : std::unary_function<typename T::RET, typename T::ARG>
{
};
int main()
{
F<decltype(FW(f))> o;
}
Say I have a template declaration like this:
template <class A, class B, class C = A (&)(B)>
How would I make it so that I could have a variable amount of objects of type C? Doing class C ...c = x won't work because variadic template arguments can't have default values. So this is what I've tried:
template <typename T>
struct helper;
template <typename F, typename B>
struct helper<F(B)> {
typedef F (&type)(B);
};
template <class F, class B, typename helper<F(B)>::type ... C>
void f(C ...c) { // error
}
But up to the last part I get error messages. I don't think I'm doing this right. What am I doing wrong here?
I think you can use the following approach. First, some machinery for type traits. This allows you to determine if the types in an argument pack are homogeneous (I guess you want all functions to have the same signature):
struct null_type { };
// Declare primary template
template<typename... Ts>
struct homogeneous_type;
// Base step
template<typename T>
struct homogeneous_type<T>
{
using type = T;
static const bool isHomogeneous = true;
};
// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
// The underlying type of the tail of the parameter pack
using type_of_remaining_parameters = typename
homogeneous_type<Ts...>::type;
// True if each parameter in the pack has the same type
static const bool isHomogeneous =
is_same<T, type_of_remaining_parameters>::value;
// If isHomogeneous is "false", the underlying type is a fictitious type
using type = typename conditional<isHomogeneous, T, null_type>::type;
};
// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
Then, some more type traits to figure out the signature of a generic function:
template<typename T>
struct signature;
template<typename A, typename B>
struct signature<A (&)(B)>
{
using ret_type = A;
using arg_type = B;
};
And finally, this is how you would define your variadic function template:
template <typename... F>
void foo(F&&... f)
{
static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
using fxn_type = typename homogeneous_type<F...>::type;
// This was template parameter A in your original code
using ret_type = typename signature<fxn_type>::ret_type;
// This was template parameter B in your original code
using arg_type = typename signature<fxn_type>::arg_type;
// ...
}
Here is a short test:
int fxn1(double) { }
int fxn2(double) { }
int fxn3(string) { }
int main()
{
foo(fxn1, fxn2); // OK
foo(fxn1, fxn2, fxn3); // ERROR! not homogeneous signatures
return 0;
}
Finally, if you need an inspiration on what to do once you have that argument pack, you can check out a small library I wrote (from which part of the machinery used in this answer is taken). An easy way to call all the functions in the argument pack F... f is the following (credits to #MarkGlisse):
initializer_list<int>{(f(forward<ArgType>(arg)), 0)...};
You can easily wrap that in a macro (just see Mark's answer to the link I posted).
Here is a complete, compilable program:
#include <iostream>
#include <type_traits>
using namespace std;
struct null_type { };
// Declare primary template
template<typename... Ts>
struct homogeneous_type;
// Base step
template<typename T>
struct homogeneous_type<T>
{
using type = T;
static const bool isHomogeneous = true;
};
// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
// The underlying type of the tail of the parameter pack
using type_of_remaining_parameters = typename
homogeneous_type<Ts...>::type;
// True if each parameter in the pack has the same type
static const bool isHomogeneous =
is_same<T, type_of_remaining_parameters>::value;
// If isHomogeneous is "false", the underlying type is a fictitious type
using type = typename conditional<isHomogeneous, T, null_type>::type;
};
// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
template<typename T>
struct signature;
template<typename A, typename B>
struct signature<A (&)(B)>
{
using ret_type = A;
using arg_type = B;
};
template <typename F>
void foo(F&& f)
{
cout << f(42) << endl;
}
template <typename... F>
void foo(typename homogeneous_type<F...>::type f, F&&... fs)
{
static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
using fxn_type = typename homogeneous_type<F...>::type;
// This was template parameter A in your original code
using ret_type = typename signature<fxn_type>::ret_type;
// This was template parameter B in your original code
using arg_type = typename signature<fxn_type>::arg_type;
cout << f(42) << endl;
foo(fs...);
}
int fxn1(double i) { return i + 1; }
int fxn2(double i) { return i * 2; }
int fxn3(double i) { return i / 2; }
int fxn4(string s) { return 0; }
int main()
{
foo(fxn1, fxn2, fxn3); // OK
// foo(fxn1, fxn2, fxn4); // ERROR! not homogeneous signatures
return 0;
}
template <typename T>
struct helper;
template <typename F, typename B>
struct helper<F(B)> {
typedef F (*type)(B);
};
template<class F, class B>
void f()
{
}
template <class F, class B, typename... C>
void f(typename helper<F(B)>::type x, C... c)
{
std::cout << x(B(10)) << '\n';
f<F,B>(c...);
}
int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int main()
{
f<int,int>(identity,half,square,cube);
}
Here's a modified version that can deduce types:
template<class F, class B>
void f(F(*x)(B))
{
x(B());
}
template <class F, class B, typename... C>
void f(F(*x)(B), C... c)
{
f(x);
f<F,B>(c...);
}
int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int string_to_int(std::string) { return 42; }
int main()
{
f(identity,half,square,cube);
// f(identity,half,string_to_int);
}