I have a problem, I defined a template class to cope with systems of different dimensions as a follow:
template <std::size_t N>
class system {
std::array<cv::Mat, N> matrices;
...
};
then I need to define different function that takes different parameters based on the size of the system. Something like that:
template <>
template<typename T>
void system<1>::fun(T & a){ }
template <>
template<typename T>
void system<2>::fun(T & a, T & b){ }
template <>
template<typename T>
void system<3>::fun(T & a, T & b, T & c){ }
However tried to uses this strategy the compiler gives the following error:
Out-of-line definition of 'fun' does not match any declaration in 'system<3>'
Moreover I would like that the headers functions will be autogenerate based on the template parameter N. I tried to use variadic template but without fortune.
I believe you could also make foo more generic using integer_sequence and alias template. (integer_sequence is c++14 but there exist c++11 implementations as well):
#include <utility>
#include <array>
template <class T, std::size_t>
using typer = T;
template <std::size_t N, class = std::make_index_sequence<N>>
struct S;
template <std::size_t N, std::size_t... Is>
struct S<N, std::index_sequence<Is...>>{
std::array<int, N> matrices;
template <class T>
void foo(typer<const T&, Is>... args) {
int dummy[] = { ((matrices[Is] = args), void(), 0)... };
static_cast<void>(dummy);
}
};
int main() {
S<3> s;
s.foo(1, 2, 3);
}
[live demo]
If you can auto generate based on N, I guess that you can write the code to do what you need generically (your comment that you tried to use variadics reinforces that).
The fact that your function is also templated on T unfortunately complicates things a little more than I would like. There are simpler solutions than what I will give, but the only ones I saw require you to either specify the type explicitly, or defer checking to runtime that could be done at compile time. As it stands, the only way I can see to do what you want is to use variadic templates. This gets most of what you want:
template <std::size_t N>
class System {
template <class ... Ts>
void fun(Ts& ts) {
static_assert(sizeof...(Ts) == N, "Wrong number of parameters!");
}
};
I've static asserted rather than enable if, to keep things simpler (and it since it's highly unlikely it will make a difference unless you plan to have another member function named fun... don't do that). Now, this function will only accept being called with N arguments, but it will allow all the types to vary. You want them all to be the same. So we need a bit of TMP.
template <class ... Ts>
struct all_same{};
template <class T>
struct all_same<T> : std::true_type {
using same_type = T;
};
template <class T, class ... Ts>
struct all_same<T, T, Ts...> : all_same<T, Ts...> {};
template <class T1, class T2, class ... Ts>
struct all_same<T1, T2, Ts...> : std::false_type {};
Some classic recursive TMP gets us what we want. Both a true false indicator of whether all the types in the pack are the same, and if they are the same we can access the common type. Once we have a common type, and have verified the size, we can use the pack to initialize an array and loop over it, so we don't have to keep doing annoying variadic style programming inside our function:
template <std::size_t N>
struct System {
template <class ... Ts>
void fun(Ts&... ts) {
static_assert(sizeof...(Ts) == N, "Wrong number of parameters!");
using same = all_same<Ts...>;
static_assert(same::value, "All types must be the same!");
std::array<std::reference_wrapper<typename same::same_type>, N> x{ts...};
for (auto& e : x) { std::cerr << e << std::endl; }
}
};
Modifying this solution to suit your exact needs will require a bit of expertise in C++, and also you'll need to watch our for certain tricky situations, e.g. when you pass both string literals and std::strings or other types that you are used to being implicitly convertible, it will fail. Still, hope this helps get you going. Live example: http://coliru.stacked-crooked.com/a/08ac23da33deb8ef.
A possible solution can be define the function inside the body of the class (en passant: avoid the name system(): can collide with the standard function), using SFINAE, as follows
template <std::size_t N>
class systemClass
{
private:
std::array<FooType, N> matrices;
public:
template<typename T, std::size_t M = N>
typename std::enable_if<M == 1U>::type fun(T & a) { }
template<typename T, std::size_t M = N>
typename std::enable_if<M == 2U>::type fun(T & a, T & b) { }
template<typename T, std::size_t M = N>
typename std::enable_if<M == 3U>::type fun(T & a, T & b, T & c) { }
};
Moreover I would like that the headers functions will be autogenerate based on the template parameter N. I tried to use variadic template but without fortune.
I'm agree with UnholySheep: isn't clear to me what do you exactly want but I suspect that a solution could be a shell script to generate the code.
You can make your function variadic, but only accepting the right number of parameter. It would look like this:
template <std::size_t N>
struct system {
template<typename... Ts>
auto fun(Ts&&... ts) -> std::enable_if_t<(N == sizeof...(Ts))> {
// function content
}
private:
std::array<cv::Mat, N> matrices;
};
The enable if will only allow the function to exist if the number of parameters is equal to N.
Related
I'm trying to create a function that takes two parameter packs of objects. There are two templated base classes and I'd like to pass instances of derived classes to this function. Consider this example.
template <int N>
struct First {};
template <int N>
struct Second {};
// there are a few of these
struct FirstImpl : First<5> {};
struct SecondImpl : Second<7> {};
template <int... firstInts, int... secondInts>
void function(float f, First<firstInts> &... first, Second<secondInts> &... second) {
// ...
}
What I would like to do is call function like this
FirstImpl firstImpl;
OtherFirstImpl otherFirstImpl;
SecondImpl secondImpl;
OtherSecondImpl otherSecondImpl;
function(9.5f, firstImpl, otherFirstImpl, secondImpl, otherSecondImpl);
but this example won't compile. The compiler seems to be trying to pack everything into the second parameter pack and failing because FirstImpl can't be implicitly converted Second<N>.
How do I get around this?
It's pretty much next to impossible to define something with two variadic parameter packs. Once a variadic parameter pack gets encountered, it likes to consume all remaining parameters, leaving no crumbs for the second pack to feed on.
However, as I mentioned, in many cases you can use tuples, and with deduction guides in C++17, the calling convention is only slightly longer than otherwise.
Tested with gcc 7.3.1, in -std=c++17 mode:
#include <tuple>
template <int N>
struct First {};
template <int N>
struct Second {};
template <int... firstInts, int... secondInts>
void function(std::tuple<First<firstInts>...> a,
std::tuple<Second<secondInts>...> b)
{
}
int main(int, char* [])
{
function( std::tuple{ First<4>{}, First<3>{} },
std::tuple{ Second<1>{}, Second<4>{} });
}
That's the basic idea. In your case, you have subclasses to deal with, so a more sophisticated approach would be necessary, probably with an initial declaration of two tuples being just a generic std::tuple< First...> and std::tuple<Second...>, with some additional template-fu. Probably need to have First and Second declare their own type in a class member declaration, and then have the aforementioned template-fu look for the class member, and figure out which superclass it's dealing with.
But the above is the basic idea of how to designate two sets of parameters, from a single variadic parameter list, and then work with it further...
Let's first code a variable template which determines whether a type derives from First or not:
template <int N>
constexpr std::true_type is_first(First<N> const &) { return {}; }
template <int N>
constexpr std::false_type is_first(Second<N> const &) { return {}; }
template <class T>
constexpr bool is_first_v = decltype( is_first(std::declval<T>()) )::value;
And a struct Split which collects the indices of the First and Second types:
template <class, class, class, std::size_t I = 0> struct Split;
template <
std::size_t... FirstInts,
std::size_t... SecondInts,
std::size_t N
>
struct Split<
std::index_sequence<FirstInts...>,
std::index_sequence<SecondInts...>,
std::tuple<>,
N
> {
using firsts = std::index_sequence<FirstInts...>;
using seconds = std::index_sequence<SecondInts...>;
};
template <
std::size_t... FirstInts,
std::size_t... SecondInts,
std::size_t I,
typename T,
typename... Tail
>
struct Split<
std::index_sequence<FirstInts...>,
std::index_sequence<SecondInts...>,
std::tuple<T, Tail...>,
I
> : std::conditional_t<
is_first_v<T>,
Split<std::index_sequence<FirstInts..., I>,
std::index_sequence<SecondInts...>,
std::tuple<Tail...>,
I + 1
>,
Split<std::index_sequence<FirstInts...>,
std::index_sequence<SecondInts..., I>,
std::tuple<Tail...>,
I + 1
>
> {};
And like I told you in the comments, adding a member value to First and Second (or inheriting from std:integral_constant), this allows us to write the following:
template <std::size_t... FirstIdx, std::size_t... SecondIdx, typename Tuple>
void function_impl(float f, std::index_sequence<FirstIdx...>, std::index_sequence<SecondIdx...>, Tuple const & tup) {
((std::cout << "firstInts: ") << ... << std::get<FirstIdx>(tup).value) << '\n';
((std::cout << "secondInts: ") << ... << std::get<SecondIdx>(tup).value) << '\n';
// your implementation
}
template <class... Args>
void function(float f, Args&&... args) {
using split = Split<std::index_sequence<>,std::index_sequence<>, std::tuple<std::decay_t<Args>...>>;
function_impl(f, typename split::firsts{}, typename split::seconds{}, std::forward_as_tuple(args...));
}
Demo
Why won't you simply pass the class itself as template parameter? Like this:
template <int N>
struct First {};
template <int N>
struct Second {};
// there are a few of these
struct FirstImpl : First<5> {};
struct SecondImpl : Second<7> {};
template <typename FirstSpec, typename SecondSpec>
void function(float f, FirstSpec & first, SecondSpec & second) {
// ...
}
Not exactly what you asked but... you could unify the two list using a variadic template-template int container (Cnt, in the following example) and next detect, for every argument, if is a First or a Second (see the use of std::is_same_v)
The following is a full working example
#include <string>
#include <vector>
#include <iostream>
#include <type_traits>
template <int>
struct First {};
template <int>
struct Second {};
// there are a few of these
struct FirstImpl : First<5> {};
struct SecondImpl : Second<7> {};
template <template <int> class ... Cnt, int... Ints>
void function (float f, Cnt<Ints> & ... args)
{
(std::cout << ... << std::is_same_v<Cnt<Ints>, First<Ints>>);
}
int main()
{
FirstImpl firstImpl;
FirstImpl otherFirstImpl;
SecondImpl secondImpl;
SecondImpl otherSecondImpl;
function(9.5f, firstImpl, otherFirstImpl, secondImpl, otherSecondImpl);
}
Recently I designed meta-types and the possible operations that would allow compile-time type concatenations:
#include <tuple>
template<template<typename...> typename T>
struct MetaTypeTag
{};
/*variable template helper*/
template<template<typename...> typename T>
constexpr MetaTypeTag<T> meta_type_tag = {};
template<typename T>
struct TypeTag
{};
/*comparison*/
template<typename T>
constexpr bool operator==(TypeTag<T>, TypeTag<T>) { return true; }
template<typename T, typename U>
constexpr bool operator==(TypeTag<T>, TypeTag<U>) { return false; }
/*variable template helper*/
template<typename T>
constexpr TypeTag<T> type_tag = {};
template<template<typename...> typename T, typename... Ts>
constexpr TypeTag<T<Ts...>> combine(MetaTypeTag<T>, TypeTag<Ts>...)
{
return {};
}
int main()
{
constexpr auto combined_tag = combine(meta_type_tag<std::tuple>, type_tag<int>, type_tag<float>);
static_assert(combined_tag == type_tag<std::tuple<int, float>>, "");
}
The std::tuple without template arguments cannot be used as a type, but may still appear in the template template parameter.
Now if we try to go one step further, the question is whether there is any way to unify struct MetaTypeTag and struct TypeTag, since they are both empty classes with one template parameter, or at least it could be possible to use the same variable template type_tag but redirect to a different class depending on the type category? So I would imagine something like this:
template<???>
constexpr auto type_tag = ????{};
//use with 'incomplete type'
type_tag<std::tuple> //MetaTypeTag<std::tuple>
//use with regular type
type_tag<int> //TypeTag<int>
I tried all possible ways - redefinition, explicit specialization, partial specialization, optional template parameters, conditional using alias, but none worked. I had hoped C++17's template<auto> would help, but it turns out that one is for non-type only.
the question is whether there is any way to unify struct MetaTypeTag and struct TypeTag, since they are both empty classes with one template parameter
I don't thinks so.
The best I can imagine to simplify a little (very a little) your code is define a couple of overloaded constexpr function, say getTag()
template <typename T>
auto constexpr getTag ()
{ return TypeTag<T>{}; }
template <template <typename ...> typename T>
auto constexpr getTag ()
{ return MetaTypeTag<T>{}; }
so you can call getTag<T>() where T is either a type or a template.
So you can call combine() as follows
constexpr auto combined_tag
= combine(getTag<std::tuple>(), getTag<int>(), getTag<float>());
But I don't think is a great improvement.
I have the following type trait:
template <class T>
struct Arity : Arity<decltype(&T::operator())> {};
template <class T, class R, class... Args>
struct Arity<R(T::*)(Args...)> {
static constexpr auto value = sizeof...(Args);
};
template <class T, class R, class... Args>
struct Arity<R(T::*)(Args...) const> {
static constexpr auto value = sizeof...(Args);
};
template <class R, class... Args>
struct Arity<R(*)(Args...)> {
static constexpr auto value = sizeof...(Args);
};
Which works great to find the number of arguments a function takes for most use cases, but it fails for one common case:
auto l1 = [](int, double){};
Arity<decltype(l1)>::value; // works, 2
auto l2 = [](auto, auto){};
Arity<decltype(l2)>::value; // error: Reference to overloaded function could not be resolved; did you mean to call it?
I believe it's impossible to generally make this work for any templated function / operator() because depending on the types/values passed as template types, a different overload could be selected, or perhaps no overload may be available at all. Also, there's no way to know what valid types and values to pass as template arguments. But still, I want this to work for the common case of a lambda taking auto arguments. Is there any way to make this more robust and cover lambdas which take auto arguments?
I guess I achieved half of a solution here. Only works up to a fixed number of parameters, but for most applications that shouldn't be an issue. Also, it's probably highly simplifiable but my brain is not into tricky SFINAE right now.
template <
class, std::size_t N,
class = std::make_index_sequence<N>,
class = void_t<>
>
struct CanCall : std::false_type { };
template <class F, std::size_t N, std::size_t... Idx>
struct CanCall<
F, N,
std::index_sequence<Idx...>,
void_t<decltype(std::declval<F>()((Idx, std::declval<Any const&&>())...))>
> : std::true_type { };
CanCall<F, N> will return whether F is callable with N parameters of arbitrary type. The Any helper type has templated implicit conversion operators that allows it to morph into any desired parameter type.
template <class F, std::size_t N = 0u, class = void>
struct Arity : Arity<F, N + 1u, void> { };
template <class F, std::size_t N>
struct Arity<F, N, std::enable_if_t<CanCall<F, N>::value>>
: std::integral_constant<std::size_t, N> { };
template <class F>
struct Arity<F, MAX_ARITY_PROBING, void>
: std::integral_constant<std::size_t, ARITY_VARIADIC> { };
Arity<F> just checks whether an F can be called with zero, one, two... parameters. First positive check wins. If we reach MAX_ARITY_PROBING parameters, Arity bails out and supposes that the function is either variadic, or is not a function at all.
See it live on Coliru
I don't think you can use lambda functions in your use case whose argument types are auto. The operator() functions of such lambda functions are most likely implemented using function templates.
Hence, decltype can't be used with:
auto l2 = [](auto, auto){};
Arity<decltype(l2)>::value;
See this answer to another SO question for more on the subject.
I'm trying to do some "template metaprogramming" stuff to make exposing c++ functions to python a bit easier. What I'd like to do is take an existing function and generating a string containing info about its return type and arguments (a typeinfo would be fine too).
I'm using a function traits class based off (stolen from) this wordpress article, but rather than hard code accesses to the first few arguments I'd like to iterate through them all.
I gather that I need make a template function that takes a size_t value for the argument index (since it must be constant), but that's where I get a bit lost.
I've written some code, but I can't get it to work in the most basic of cases (let alone the generic case that I'm after.)
// The stolen function_traits struct...thing
template<typename T>
struct function_traits;
template<typename R, typename ...Args>
struct function_traits<std::function<R(Args...)>>
{
static const size_t nargs = sizeof...(Args);
using result_type = R;
template <size_t i>
struct arg
{
using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
};
};
// The function of interest
int foo(float x) {
return int(x);
}
// Recurse until one argument is left, appending the type name
// to the referenced string being passed in
template<size_t argIdx, typename R, typename ... Args>
void getArgTypes(std::string& ref)
{
using fun = function_traits<std::function<R(Args...)> >;
if (argIdx == 1)
ref.append(typeid(fun::arg<0>).name()).append("\n");
else {
ref.append(typeid(fun::arg<argIdx-1>).name()).append("\n");
getArgTypes<argIdx - 1, R, Args...>(ref);
}
}
// My test of the template function
void test() {
std::string f = "";
// What I'd like to do
using fun = function_traits<std::function<decltype(foo)> >;
getArgTypes<fun::nargs, fun::result_type, ? ? ? >;
// But I can't even do this!
getArgTypes<1, float, int>(f);
}
In the first case, where I use my function_traits struct when calling getArgTypes, I don't know what to designate as the ... Args template parameter. In the second case MSVC throws the error:
Error C1202 recursive type or function dependency context too complex
I'm completely new to this metaprogramming / variadic templates stuff so sorry if this is a dumb question. If there's a less roundabout solution I'd also be interested.
Thank you for reading!
if (argIdx == 1) can't be a runtime condtion. It must be changed to a compile time one with std::enable_if. This is where the error comes from: a compiler tries to instantiate endlessly (recursively without a stop condition) the getArgType function template.
All dependent type names must be announced with a typename keyword, and those that refer to templates must be announced with a template keyword, e.g. typename fun::template arg<0> in place of fun::arg<0>.
fun::arg<0> itself is a struct with a nested type definition. To access it, use typename fun::template arg<0>::type syntax.
Expansion of function_traits::arg<N>::type can be done with the indices trick, in particular typename F::template arg<Is>::type....
#include <string>
#include <typeinfo>
#include <functional>
#include <utility>
#include <cstddef>
template <size_t argIdx, typename R, typename... Args>
auto getArgTypes(std::string& ref)
-> typename std::enable_if<argIdx == 1>::type
{
using fun = function_traits<std::function<R(Args...)> >;
ref.append(typeid(typename fun::template arg<0>::type).name()).append(" ");
}
template <size_t argIdx, typename R, typename... Args>
auto getArgTypes(std::string& ref)
-> typename std::enable_if<argIdx != 1>::type
{
using fun = function_traits<std::function<R(Args...)> >;
ref.append(typeid(typename fun::template arg<argIdx-1>::type).name()).append(" ");
getArgTypes<argIdx - 1, R, Args...>(ref);
}
template <typename F, std::size_t... Is>
void test2(std::index_sequence<Is...>)
{
std::string s;
getArgTypes<F::nargs, typename F::result_type, typename F::template arg<Is>::type...>(s);
std::cout << s;
}
void test()
{
using F = function_traits<std::function<decltype(foo)>>;
test2<F>(std::make_index_sequence<F::nargs>{});
}
DEMO
Very basic index_sequence implementation goes as follows:
template <std::size_t...> struct index_sequence {};
template <std::size_t N, std::size_t... Is> struct make_index_sequence : make_index_sequence<N-1, N-1, Is...> {};
template <std::size_t... Is> struct make_index_sequence<0, Is...> : index_sequence<Is...> {};
I am trying to create a template class that executes a user-specified N-ary function with arguments of type C. To do so, I need some way of specifying the type of this function based on the template parameters. The following code illustrates my problem:
template <typename C, size_t N>
class NaryDispatch {
typedef typename std::function<void(/* N parameters of type C& */)> NaryFn;
public:
NaryDispatch(NaryFn f) : m_function(std::forward<NaryFn>(f)) {}
private:
NaryFn m_function;
};
I have been unable to find a way to build the std::function type with a signature of the appropriate arity. I am using C++11 and Boost::MPL extensively so solutions involving either are more than welcome. I have tried to use SFINAE/template parameter deduction on the constructor parameter as follows:
template <
class... Args,
typename std::enable_if<sizeof...(Args) == N, C>::type = 0
>
NaryDispatch(std::function<void(Args&...)> fn) : m_function(std::forward<???>(fn)) {}
As you can see, the issue here is that because I have been unable to determine the type the function will take given the template parameters C and N, I'm unable to determine the type of the class member where the function should be stored.
To simplify my intent a bit, for template parameters C and N, the class constructor should accept (and store in a private member) an std::function that returns void and accepts N parameters of type C&. For example, the following should compile:
NaryDispatch<int, 3> disp([](int a, int b, int c) {});
Thanks in advance for any insights you might offer.
This shouldn't be too hard. Let's start with the top level:
template <typename C, std::size_t N>
struct NaryDispatch
{
// details, see below
using f_type = typename function_maker<C &, N>::type;
template <typename F>
NaryDispatch(F && f) : fn_(std::forward<F>(f)) {}
f_type fn_;
};
Now we just need to implement the trait function_maker:
template <typename T, std::size_t K, typename ...Args>
struct function_maker
{
using type = typename function_maker<T, K - 1, T, Args...>::type;
};
template <typename T, typename ...Args>
struct function_maker<T, 0, Args...>
{
using type = std::function<void(Args...)>;
};
Finally, you might also want to provide some kind of constrained call function. Perhaps like this:
template <typename ...Args,
typename = typename std::enable_if<sizeof...(Args) == N>::type>
void run(Args &&... args)
{
fn_(std::forward<Args>(args)...);
}
Your next problem will be "How do I pass N parameters to the contained std::function?" I think you could simplify substantially by using a dispatcher class template that works with any old list of parameter types:
template <typename...Args>
class Dispatcher {
typedef typename std::function<void(Args...)> Fn;
public:
Dispatcher(Fn f) : m_function(std::move(f)) {}
void operator()(Args...args) {
m_function(std::forward<Args>(args)...);
}
private:
Fn m_function;
};
along with a bit of metaprogramming to calculate the proper Dispatcher specialization to handle N parameters of type C&:
template <typename C, size_t N, typename...Args>
struct NaryDispatch_ {
using type = typename NaryDispatch_<C, N-1, Args..., C&>::type;
};
template <typename C, typename...Args>
struct NaryDispatch_<C, 0, Args...> {
using type = Dispatcher<Args...>;
};
template <typename C, size_t N>
using NaryDispatch = typename NaryDispatch_<C, N>::type;
DEMO AT IDEONE