Instantiation of function template with variadic parameter pack - c++

Suppose say I have this code:
template<int... Us>
struct Matrix{};
template<int... U1, int... U2>
auto compute(Matrix<U1...>, Matrix<U2...>){return 0;}
Matrix<1> a; Matrix<2,3> b;
Matrix<1,2> c; Matrix<3> d;
int main(){
compute(a,b);
compute(c,d);
auto fp = &compute<1,2,3>;
fp(a,b);
fp(c,d);
}
Would the two compute() calls instantiate just one function template i.e. compute<1,2,3> or would there be two different instantiations depending on the arguments?
I wanted to confirm this by taking a function pointer to the particular instantiation and see if I could call the function with the 2 different sets of arguments using the same function pointer but I get the following errors at the line where I call fp(a,b):
[x86-64 gcc 8.2 #1] error: could not convert 'a' from
'Matrix<#'nontype_argument_pack' not supported by
dump_expr#<expression error>>' to 'Matrix<#'nontype_argument_pack' not
supported by dump_expr#<expression error>>'

Parameter packs are greedy.
&compute<1,2,3> is, in pseudo-code, &compute< U1={1,2,3}, U2={} >.
Getting a pointer to the individual computes is annoying.
template<class U1s, class U2s>
struct get_computer;
template<int...U1, int...U2>
struct get_computer<std::integer_sequence<int, U1...>, std::integer_sequence<int, U2...>> {
using compute_type = int(*)(Matrix<U1...>, Matrix<U2...>);
compute_type operator()() const { return compute; }
};
we can then do
auto fp1 = get_computer<std::integer_sequence<int, 1>, std::integer_sequence<int, 2, 3>>{}();
auto fp2 = get_computer<std::integer_sequence<int, 1, 2>, std::integer_sequence<int, 3>>{}();
and fp1 and fp2 are different types.

Would the two compute() calls instantiate just one function template i.e. compute<1,2,3> or would there be two different instantiations depending on the arguments?
Very differently. The function that is invoked when you write compute(a, b) is a function that takes a Matrix<1> and a Matrix<2,3>. The function that is invoked when you write compute(c, d) is a function that takes a Matrix<1,2> and a Matrix<3>.
But when you write this:
auto fp = &compute<1,2,3>;
There is no way to say which of U1... or U2... those values refer to. What every compiler does is slurp all of the arguments into the first pack - so fp ends up being a int(*)(Matrix<1,2,3>, Matrix<>). In other words, this version is a function that takes a Matrix<1,2,3> and a Matrix<>. Which is different from both of the original calls.
And indeed, since the two original calls were calls to two different functions, it would not be possible to take a single function pointer to both of them. What you could do instead is construct a function object that does the right thing:
auto fp = [](auto m1, auto m2){ return compute(m1, m2); };
This works (try it), but is a very different kind of thing.

Different approach. No need integer sequence or temporary functor object. Link: https://gcc.godbolt.org/z/W4V6gf
template<int... V1>
struct Mat1 {
template<int... V2>
struct Mat2 {
using compute_type = int(*)(Matrix<V1...>, Matrix<V2...>);
};
};
void foo() {
{
using compute_type = Mat1<1>::Mat2<2,3>::compute_type;
compute_type ct = compute;
ct(a, b);
//ct(c, d); //This wont compile
}
{
using compute_type = Mat1<1,2>::Mat2<3>::compute_type;
compute_type ct = compute;
ct(c, d);
//ct(a, b); //This wont compile
}
}
Even More Generic
template<int... Us>
struct Matrix{};
Matrix<1> a; Matrix<2,3> b;
Matrix<1,2> c; Matrix<3> d;
template<int... U1, int... U2>
auto compute(Matrix<U1...>, Matrix<U2...>){return 0;}
template<class Scalar, template<Scalar...> class MatType>
struct VArg {
template<Scalar... V1>
struct arg1 {
using type = MatType<V1...>;
template<Scalar... V2>
struct arg2 {
using type1 = type;
using type2 = MatType<V2...>;
};
};
};
template<class args_gen>
struct compute_type {
using type = int(*)(typename args_gen::type1, typename args_gen::type2);
};
void foo() {
using int_matrix_gen = VArg<int, Matrix>;
{
using args_ab = int_matrix_gen::arg1<1>::arg2<2,3>;
compute_type<args_ab>::type cptr = compute;
cptr(a, b);
//cptr(c, d); This wont compile
}
{
using args_cd = int_matrix_gen::arg1<1,2>::arg2<3>;
compute_type<args_cd>::type cptr = compute;
cptr(c, d);
//cptr(a, b); This wont compile
}
}
Even more Generic'er: https://gcc.godbolt.org/z/EF6OK9 supporting functions with 3 Matrix arguments.

Related

Can we create an std::array of pointers to object in a constexpr function and return it?

Suppose we have some sort of templated struct:
template<typename T>
struct S {};
We want to create an std::array of some object of type S. But, because S is a template struct, we need to create a base class for keeping those objects.
struct AbstractS {};
template<typename T>
struct S : AbstractS {};
Now, suppose that we have a constexpr function that creates an std::array and returns it and a constexpr function for get that array.
constexpr auto createArray() {
constexpr auto v1 = S<int>{};
constexpr auto v2 = S<double>{};
std::array<const AbstractS *, 2> values{ &v1, &v2 };
return values;
}
constexpr void getArray() {
constexpr auto values = createArray();
}
This code doesn't compile and I think this is because the addresses of v1 and v2 are not constants.
Let me give you a concrete example of what I'm trying to do.
struct AbstractPolynomial {};
template<typename T, std::size_t Degree>
struct Polynomial : AbstractPolynomial {};
I have a struct that models a polynomial function, where T is type of values of coefficients of polynomial and Degree is the polynomial Degree.
template<std::size_t N>
constexpr auto createArray() {
std::array<AbstractPolynomial *, N> polynomials;
for (std::size_t i = 0; i < N; i++) {
if (i % 2 == 0) {
polynomials[i] = &Polynomials<T1>{5};
} else {
polynomials[i] = &Polynomials<T2>{2, 5};
}
}
return polynomials;
}
Suppose that Polynomial has a deduction guide (I didn't implement it here). I know that you cannot get the address of a temporary and assigning lines are incorrect, but I put in this form because I want you to give me a solution for this scenario.
Can we do some sort of tricks to create a scenario like this?
This is the solution, note that the Polynomials need to be generated initially preserving their compile-time type.
The later choice to not use that information for whatever reason (dynamic access) is yours.
Note the data structure is constexpr, but not necessarily the evaluation of the polynomial.
I think this is because virtual interferes with the constexpr-ness capabilities of the evaluate function.
You can play with the solution here: https://godbolt.org/z/oMreTzoGP
#include<array>
#include<cassert>
#include<tuple>
#include<utility>
// Dynamic polymials (questionable use of virtual functions)
struct AbstractPolynomial {
virtual auto evaluate() const -> double = 0;
};
template<typename T>
struct Polynomial : AbstractPolynomial {
constexpr Polynomial(T t) : value_{t}{}
T value_;
auto evaluate() const -> double override;
};
// instantiate and define two child classes for illustration
template<> auto Polynomial<double >::evaluate() const -> double {return value_;}
template<> auto Polynomial<std::pair<double, double>>::evaluate() const -> double {return value_.first + value_.second;}
// Metaprogramming in this block doesn't assume virtual functions, Polynomial can be a concrete class
// functional form (on index and constructor args) taken from OP example
constexpr auto makePoly(std::integral_constant<int, 0>){return Polynomial<double >{5.};}
constexpr auto makePoly(std::integral_constant<int, 1>){return Polynomial<std::pair<double, double>>({2., 5.});}
// Tuples (not arrays) are created here
template <std::size_t... I>
constexpr auto createTuple_aux(std::index_sequence<I...>){
// do different things for even/odd cases (again taken from OP example)
return std::make_tuple(makePoly(std::integral_constant<int, I % 2>{})...);
}
template <std::size_t N> constexpr auto createTuple(){return createTuple_aux(std::make_index_sequence<N>{});}
// create 10 non-polymorphic polynamials in a tuple (preserve type information)
constexpr auto polyTuple = createTuple<10>();
// create 10 polymorphic polynamials in an array via pointers (type information is kept in the virtual table in pointer elements)
constexpr auto polyArrayPtr = std::apply([](auto const&... e){return std::array<AbstractPolynomial const*, std::tuple_size<decltype(polyTuple)>{}>{&e...};}, polyTuple);
int main(){
// test non-polymorphic access
assert( std::get<0>(polyTuple).evaluate() == 5. );
assert( std::get<1>(polyTuple).evaluate() == 7. );
assert( std::get<2>(polyTuple).evaluate() == 5. );
// test polymorphic access, indiraction
constexpr auto check = polyArrayPtr.size();
assert( polyArrayPtr[0]->evaluate() == 5. );
assert( polyArrayPtr[1]->evaluate() == 7. );
assert( polyArrayPtr[2]->evaluate() == 5. );
}
I am not an expert in constexpr. But intuition tells me your elements must be global and, for example, static to the function.
Since this is not possible in a constexpr function (the compiler tells me) I put them outside and the whole thing works.
#include<array>
struct AbstractS {};
template<typename T>
struct S : AbstractS {};
namespace detail{
constexpr auto v1 = S<int>{};
constexpr auto v2 = S<double>{};
}
constexpr auto createArray() {
constexpr std::array<const AbstractS *, 2> values{ &detail::v1, &detail::v2 };
return values;
}
constexpr void getArray() {
constexpr auto values = createArray();
}
int main(){}
https://godbolt.org/z/1q6MbMhdM

Specifying default parameter when calling C++ function

Suppose I have code like this:
void f(int a = 0, int b = 0, int c = 0)
{
//...Some Code...
}
As you can evidently see above with my code, the parameters a,b, and c have default parameter values of 0. Now take a look at my main function below:
int main()
{
//Here are 4 ways of calling the above function:
int a = 2;
int b = 3;
int c = -1;
f(a, b, c);
f(a, b);
f(a);
f();
//note the above parameters could be changed for the other variables
//as well.
}
Now I know that I can't just skip a parameter, and let it have the default value, because that value would evaluate as the parameter at that position. What I mean is, that I cannot, say call, f(a,c), because, c would be evaluated as b, which is what I don't want, especially if c is the wrong type. Is there a way for the calling function to specify in C++, to use whatever default parameter value there is for the function in any given position, without being limited to going backwards from the last parameter to none? Is there any reserved keyword to achieve this, or at least a work-around? An example I can give would be like:
f(a, def, c) //Where def would mean default.
There isn't a reserved word for this, and f(a,,c) is not valid either. You can omit a number of rightmost optional parameters, as you show, but not the middle one like that.
http://www.learncpp.com/cpp-tutorial/77-default-parameters/
Quoting directly from the link above:
Multiple default parameters
A function can have multiple default parameters:
void printValues(int x=10, int y=20, int z=30)
{
std::cout << "Values: " << x << " " << y << " " << z << '\n';
}
Given the following function calls:
printValues(1, 2, 3);
printValues(1, 2);
printValues(1);
printValues();
The following output is produced:
Values: 1 2 3
Values: 1 2 30
Values: 1 20 30
Values: 10 20 30
Note that it is impossible to supply a user-defined value for z
without also supplying a value for x and y. This is because C++ does
not support a function call syntax such as printValues(,,3). This has
two major consequences:
1) All default parameters must be the rightmost parameters. The
following is not allowed:
void printValue(int x=10, int y); // not allowed
2) If more than one default parameter exists, the leftmost default
parameter should be the one most likely to be explicitly set by the
user.
As workaround, you may (ab)use boost::optional (until std::optional from c++17):
void f(boost::optional<int> oa = boost::none,
boost::optional<int> ob = boost::none,
boost::optional<int> oc = boost::none)
{
int a = oa.value_or(0); // Real default value go here
int b = ob.value_or(0); // Real default value go here
int c = oc.value_or(0); // Real default value go here
//...Some Code...
}
and then call it
f(a, boost::none, c);
Not exactly what you asked for, but you can use std::bind() to fix a value for a parameter.
Something like
#include <functional>
void f(int a = 0, int b = 0, int c = 0)
{
//...Some Code...
}
int main()
{
// Here are 4 ways of calling the above function:
int a = 2;
int b = 3;
int c = -1;
f(a, b, c);
f(a, b);
f(a);
f();
// note the above parameters could be changed
// for the other variables as well.
using namespace std::placeholders; // for _1, _2
auto f1 = std::bind(f, _1, 0, _2);
f1(a, c); // call f(a, 0, c);
return 0;
}
With std::bind() you can fix values different from default parameters' values or values for parameters without default values.
Take into account that std::bind() is available only from C++11.
You already have an accepted answer, but here's another workaround (that - I believe - has advantages over the other proposed workarounds):
You can strong-type the arguments:
struct A { int value = 0; };
struct B { int value = 2; };
struct C { int value = 4; };
void f(A a = {}, B b = {}, C c = {}) {}
void f(A a, C c) {}
int main()
{
auto a = 0;
auto b = -5;
auto c = 1;
f(a, b, c);
f(a, C{2});
f({}, {}, 3);
}
Advantages:
it's simple and easy to maintain (one line per argument).
provides a natural point for constricting the API further (for example, "throw if B's value is negative").
it doesn't get in the way (works with default construction, works with intellisense/auto-complete/whatever as good as any other class)
it is self-documenting.
it's as fast as the native version.
Disadvantages:
increases name pollution (better put all this in a namespace).
while simple, it is still more code to maintain (than just defining the function directly).
it may raise a few eyebrows (consider adding a comment on why strong-typing is needed)
If all parameters of the function were of distinct types, you could find out which parameters were passed and which were not and choose the default value for the latter.
In order to achieve the distinct type requirement, you can wrap your parameters and pass it to a variadic function template.
Then even the order of the argument does not matter anymore:
#include <tuple>
#include <iostream>
#include <type_traits>
// -----
// from http://stackoverflow.com/a/25958302/678093
template <typename T, typename Tuple>
struct has_type;
template <typename T>
struct has_type<T, std::tuple<>> : std::false_type {};
template <typename T, typename U, typename... Ts>
struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {};
template <typename T, typename... Ts>
struct has_type<T, std::tuple<T, Ts...>> : std::true_type {};
template <typename T, typename Tuple>
using tuple_contains_type = typename has_type<T, Tuple>::type;
//------
template <typename Tag, typename T, T def>
struct Value{
Value() : v(def){}
Value(T v) : v(v){}
T v;
};
using A = Value<struct A_, int, 1>;
using B = Value<struct B_, int, 2>;
using C = Value<struct C_, int, 3>;
template <typename T, typename Tuple>
std::enable_if_t<tuple_contains_type<T, Tuple>::value, T> getValueOrDefaultImpl(Tuple t)
{
return std::get<T>(t);
}
template <typename T, typename Tuple>
std::enable_if_t<!tuple_contains_type<T, Tuple>::value, T> getValueOrDefaultImpl(Tuple)
{
return T{};
}
template <typename InputTuple, typename... Params>
auto getValueOrDefault(std::tuple<Params...>, InputTuple t)
{
return std::make_tuple(getValueOrDefaultImpl<Params>(t)...);
}
template <typename... Params, typename ArgTuple>
auto getParams(ArgTuple argTuple)
{
using ParamTuple = std::tuple<Params...>;
ParamTuple allValues = getValueOrDefault(ParamTuple{}, argTuple);
return allValues;
}
template <typename... Args>
void f(Args ... args)
{
auto allParams = getParams<A,B,C>(std::make_tuple(args...));
std::cout << "a = " << std::get<A>(allParams).v << " b = " << std::get<B>(allParams).v << " c = " << std::get<C>(allParams).v << std::endl;
}
int main()
{
A a{10};
B b{100};
C c{1000};
f(a, b, c);
f(b, c, a);
f(a, b);
f(a);
f();
}
output
a = 10 b = 100 c = 1000
a = 10 b = 100 c = 1000
a = 10 b = 100 c = 3
a = 10 b = 2 c = 3
a = 1 b = 2 c = 3
live example
I will just use static functions to define default values that can change:
class defValsExample
{
public:
defValsExample() {
}
static int f1def_a() { return 1; }
static int f1def_b() { return 2; }
int f1(int a = f1def_a(), int b = f1def_b()) {
return a+b;
}
};
int main()
{
defValsExample t;
int c = t.f1(t.f1def_a(),4);
}

c++ Default paramaters: is it possible to override a default parameter without overriding earlier default parameters

I have a function:
int function(int a, int b = 1, int c = 2){
return a+b+c;
}
I want to set the value of the "c" variable to 3, but don't want to set the value of "b"
In a language like python I can do this:
function(23,c=3)
However in c++ I cant find a way to do something like that. All examples I could find involved setting the value of "b" before the value of "c", like this:
function(23,1,3);
How can I set the value of a default parameter directly?
This is not possible in C++ (at least not directly). You have the provide all parameters up to the last one you want to provide, and in the order given by the declaration.
You can not do that in C++.
As a workaround you could wrap all parameters as fields with default value in a class (or a struct). You can then have multiple constructors for that class that allow you to set only those fields you are really interested in changing with respect to default.
It is possible in c++... if you're willing to jump through some hoops.
For fun, here is an example of how it might be done:
#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>
//
// utility to check whether a type is in a list of types
//
template<class T, class...Ts> struct is_in;
template<class T, class U>
struct is_in<T, U>
: std::is_same<T, U>::type {};
template<class T, class U, class...Rest>
struct is_in<T, U, Rest...>
: std::integral_constant<bool, std::is_same<T, U>::value || is_in<T, Rest...>::value>
{};
//
// a wrapper around fundamental types so we can 'name' types
//
template<class Type, class Tag>
struct fundamental {
using value_type = Type;
using tag_type = Tag;
fundamental(Type x) : _x(x) {}
operator const Type&() const { return _x; }
operator Type&() { return _x; }
Type _x;
};
//
// a utility to figure out a fundamental type's value or to take it's default value if it's not present
//
template<class Fundamental, class Tuple, typename = void>
struct value_of_impl
{
static typename Fundamental::value_type apply(const Tuple& t)
{
return Fundamental::tag_type::dflt;
}
};
template<class Fundamental, class...Types>
struct value_of_impl<Fundamental, std::tuple<Types...>, std::enable_if_t<is_in<Fundamental, Types...>::value>>
{
static typename Fundamental::value_type apply(const std::tuple<Types...>& t)
{
return typename Fundamental::value_type(std::get<Fundamental>(t));
}
};
template<class Fundamental, class Tuple>
decltype(auto) value_of(const Tuple& t)
{
return value_of_impl<Fundamental, Tuple>::apply(t);
}
//
// some tag names to differentiate parameter 'name' types
//
struct a_tag { static constexpr int dflt = 0; };
struct b_tag { static constexpr int dflt = 1; };
struct c_tag { static constexpr int dflt = 2; };
//
// define some parameter 'names'
//
using a = fundamental<int, a_tag>;
using b = fundamental<int, b_tag>;
using c = fundamental<int, c_tag>;
//
// the canonical implementation of the function
//
void func(int a, int b, int c)
{
std::cout << a << ", " << b << ", " << c << std::endl;
}
//
// a version that forwards the values of fundamental types in a tuple, or their default values if not present
//
template<class...Fundamentals>
void func(std::tuple<Fundamentals...> t)
{
func(value_of<a>(t),
value_of<b>(t),
value_of<c>(t));
}
//
// a version that converts a variadic argument list of fundamentals into a tuple (that we can search)
//
template<class...Fundamentals>
void func(Fundamentals&&...fs)
{
return func(std::make_tuple(fs...));
}
//
// a test
//
using namespace std;
auto main() -> int
{
func();
func(a(5));
func(c(10), a(5));
func(b(20), c(10), a(5));
return 0;
}
expected output:
0, 1, 2
5, 1, 2
5, 1, 10
5, 20, 10
You can't do that directly, but you can use Named Parameter Idiom (although criticized).
The idea is to create an object encapsulating all parameters, initialize it using method chaining and finally call the function, so the code would look like:
int v = function(params(23).c(3));
Something like this could be done with the named parameter idiom. Here's how it might look in use to have optional parameters (sans the default parameter values):
/*
int function(int a, int b = 1, int c = 2){
return a+b+c;
}
*/
int function( Parameters &p ) {
/* ... */
}
void someOtherFunction() {
function( Parameters().parmW(/*...*/)
/* parmX was omitted here */
.parmY(/*...*/)
.parmZ(/*...*/)
);
Adding default parameters could be done in a few ways. function could be replaced with a class whose purpose is to perform those actions. Parameters could also be written to know which flags were set, then function passes in default values before it begins executing. I'm sure there's plenty of ways to do this, perhaps some a lot better than what I've suggested.

Implicit conversion to template

My example below suggests that implicit conversions from non-template types to template types won't work as seamlessly as those only involving non-template types. Is there a way to make them work nonetheless?
Example:
struct point;
template<unsigned d> struct vec {
vec() { }
// ...
};
template<> struct vec<2> {
vec() { }
vec(const point& p) { /* ... */ } // Conversion constructor
// ...
};
struct point {
operator vec<2>() { return vec<2>(/* ... */); } // Conversion operator
};
template<unsigned d> vec<d> foo(vec<d> a, vec<d> b) {
return vec<d>(/* ... */);
}
template<unsigned d1, unsigned d2>
vec<d1 + d2> bar(vec<d1> a, vec<d2> b) {
return vec<d1 + d2>(/* ... */);
}
int main(int argc, char** argv) {
point p1, p2;
vec<2> v2;
vec<3> v3;
foo(v2, p1);
foo(p2, v2);
foo(p1, p2);
bar(v3, p1);
}
Is there a way to let this code auto-convert from point to vec<2>?
I know I can overload foo and bar to allow for point arguments, delegating to the vec implementation using an explicit conversion. But doing this for all parameter combinations will become tedious, particularly for functions with many such parameters. So I'm not interested in solutions where I have to duplicate code for every parameter combination of every function.
It appears that neither the conversion constructor nor the cast operator are sufficient to achieve this. At least my gcc 4.7.1 reports no matching function call, although it does name the desired function in a notice, stating that ‘point’ is not derived from ‘vec<d>’.
There is no direct way to get the conversion from point to vec<2>, because at the time when the function call foo(v1,p1) is processed, a function foo that expects a vec<2> as second argument does not exist yet. It's just a function template, and in order for this to be instantiated to a foo(const vec<2> &,const vec<2> &), a function call with these exact argument types would have to be given.
In order for the code to work, the compiler would have to guess both how to instantiate the template parameters, and what type the point argument to convert to. This is too much in the general case (although in your particular code it appears simple, because there is no other possible way to interpret the intent of the programmer).
In terms of solving this, the only thing I can think of is to create highly templated conversion functions:
template <typename T>
struct make_vec
{ };
template <unsigned d>
struct make_vec<vec<d>>
{
static constexpr unsigned dim = d;
using type = vec<dim>;
static const type &from(const type &v)
{ return v; }
};
template <>
struct make_vec<point>
{
static constexpr unsigned dim = 2;
using type = vec<dim>;
static type from(const point &p)
{ return type(p); }
};
template <typename T>
typename make_vec<typename std::decay<T>::type>::type make_vec_from(T&& arg)
{ return make_vec<typename std::decay<T>::type>::from(std::forward<T>(arg)); }
And then implement the foo and bar functions as general templates (accepting all kinds of types, not only vec<d>, using make_vec defined above to convert the given types to the right kind of vec<d>):
namespace detail {
/* Your original implementation of foo. */
template<unsigned d> vec<d> foo(vec<d>, vec<d>) {
return vec<d>(/* ... */);
}
}
/* Templated version of foo that calls the conversion functions (which do
nothing if the argument is already a vec<d>), and then calls the
foo() function defined above. */
template <typename T, typename... Ts>
typename make_vec<typename std::decay<T>::type>::type foo(T&& arg, Ts&&... args)
{ return detail::foo(make_vec_from(arg),make_vec_from(args)...); }
In the case of bar you also need a way to calculate the return type, which is vec<d1+d2+d3...>. For this, a sum calculator is required, also templated:
template <typename... Ts>
struct dsum {
static constexpr unsigned value = 0;
};
template <typename T, typename... Ts>
struct dsum<T,Ts...> {
static constexpr unsigned value = make_vec<typename std::decay<T>::type>::dim + dsum<Ts...>::value;
};
Then, the return type of bar() is vec<dsum<T,Ts...>::value>.
A fully working example is here: http://liveworkspace.org/code/nZJYu$11
Not exactly simple, but might be worth it if you really have extremely many different combinations of arguments.

template argument deduction for pointer to member function?

I am trying to build a statically bound delegate class, where the member function is bound at compile time, thereby aiding optimisation.
I have the following code which works exactly how I want it to:
#include <iostream>
namespace thr {
template<typename T, T func>
struct delegate;
template<typename R,
typename C,
typename... A,
R (C::* mem_fun)(A...)>
struct delegate<R(C::*)(A...), mem_fun>
{
delegate(C* obj_)
: _obj(obj_)
{}
R operator()(A... a)
{
return (_obj->*mem_fun)(a...);
}
private:
C* _obj;
};
} // namespace thr
struct foo
{
double bar(int i, int j)
{
return (double)i / (double)j;
}
};
int main()
{
foo f;
typedef thr::delegate<decltype(&foo::bar), &foo::bar> cb;
cb c(&f);
std::cout << c(4, 3);
return 0;
}
However, the usage is not very elegant:
thr::delegate<decltype(&foo::bar), &foo::bar>
I would like to use a function template which deduces the template parameters and returns a delegate instance; something along the lines of (this code does not compile):
template<typename C, typename T, T func>
thr::delegate<T, func> bind(T func, C* obj)
{
return thr::delegate<decltype(func), func>(obj);
}
This would allow for more elegant syntax:
auto cb = bind(&foo::bar, &f);
Is it possible to deduce a non-type parameter in a function template?
Is what I'm trying to achieve even possible?
Would std::function help? http://www2.research.att.com/~bs/C++0xFAQ.html#std-function Your example looks quite close.
I think the compiler supplied STL does pretty horrible things to make it work smoothly. You may want to have a look at as an example before giving up.
Edit: I went out and tried what you try to accomplish. My conclusion is a compile error:
The return type of the bind (delegate) must name the pointer to member because it is your own requirement.
bind should accept the name of the pointer to member to be elegant (i.e. your requirement)
Compiler requires you to not shadow the template parameter with a function parameter or use the name in both parameters and return type.
Therefore one of your requirements must go.
Edit 2: I took the liberty of changing your delegate so bind works as you wish. bind might not be your priority though.
#include <iostream>
namespace thr {
template<typename C,typename R,typename... A>
struct delegate
{
private:
C* _obj;
R(C::*_f)(A...);
public:
delegate(C* obj_,R(C::*f)(A...))
: _obj(obj_),_f(f)
{}
R operator()(A... a)
{
return (_obj->*_f)(a...);
}
};
} // namespace thr
template<class C,typename R,typename... A> thr::delegate<C,R,A...> bind(R(C::*f)(A...),C* obj){
return thr::delegate<C,R,A...>(obj,f);
}
struct foo
{
double bar(int i, int j)
{
return (double)i / (double)j;
}
};
int main()
{
foo f;
auto c = bind(&foo::bar, &f);
std::cout << c(4, 6);
return 0;
}
It is possible to deduce other entities than types in a function signature, but function parameters themselves cannot then be used as template parameters.
Given:
template <size_t I> struct Integral { static size_t const value = I; };
You can have:
template <size_t N>
Integral<N> foo(char const (&)[N]);
But you cannot have:
Integral<N> bar(size_t N);
In the former case, N as the size of the array is part of the type of the argument, in the latter case, N is the argument itself. It can be noticed that in the former case, N appeared in the template parameters list of the type signature.
Therefore, if indeed what you want is possible, the member pointer value would have to appear as part of the template parameter list of the function signature.
There may be a saving grace using constexpr, which can turn a regular value into a constant fit for template parameters:
constexpr size_t fib(size_t N) { return N <= 1 ? 1 : fib(N-1) + fib(N-2); }
Integral<fib(4)> works;
But I am not savvy enough to go down that road...
I do however have a simple question: why do you think this will speed things up ? Compilers are very good at constant propagation and inlining, to the point of being able to inline calls to virtual functions when they can assess the dynamic type of variables at compilation. Are you sure it's worth sweating over this ?