I am wondering if it is possible to pass a integer parameter of a lambda to a nested template lambda as its template argument. If it is possible then it gives a lot of advantages to use template lambda.
For example, using a template lambda is an awkward work. Considering
auto foo=[]<int N>(){
return N;
};
std::cout<<foo.operator()<5>();
Here when we are calling lambda foo, we have to invoke its native operator() with template argument <5> and then call it by another ().
So, if we can design a lambda to pass a normal integer parameter and internally the lambda call its local template lambda and do the work, it then can save all this awkwardness. I designed this simple lambda to convert parameter N to its native template lambda's argument. But I am stuck on how to call this template lambda.
auto foo=[](int N){
auto f=[]<int N>(){
return N;
};
return f.operator()<N>(); //this cannot compile!
};
My question is how I can call this f within foo? Or is this idea entirely impossible because template argument requires N to be constexpr or compile-time-constant?
Thank you for cigien's lightening fast response! It seems
this idea entirely impossible because template argument requires N to be constexpr or compile-time-constant
And further to Chris suggestion of a possible workaround, I try to solve my original template-lambda-invoking-awkwardness by using an std::integral_constant. This is how far I can get:
#define constInt(N) integral_constant<int, N>{}
auto foo=[]<int N>(std::integral_constant<int, N>&& n){
auto f=[](){
return array<int, N>{};
};
return f();
};
auto ary1=foo(integral_constant<int, 5>{});
auto ary2=foo(constInt(5));
static_assert(is_same_v<decltype(ary1), array<int, 5>>);
static_assert(is_same_v<decltype(ary2), array<int, 5>>);
By using a macro constInt, it saves a little typing work. Then my question is:
Is this the best we can achieve with template lambda invoking? What if the template parameter is a type that we cannot take advantage of std::integral_constant?
With Davis's suggestion of using a tag, I am rephrasing my question as this concrete task below:
**creating a lambda to return a std::array<T,N>
Here is usual lambda:
auto createArray=[]<typename T, size_t N>(){
return array<T, N>{};
};
But calling it is an awkward way with template parameter:
auto ary4=createArray.operator()<string, 5>();
static_assert(is_same_v<decltype(ary4), array<string, 5>>);
Can we avoid using this .operator()<string, 5> by just using normal parameter like std::itegral_constant? For example, something like createArray(class_tag<string>{},integral_constant<size_t, 5>{});
Then how should we implement this class_tag?
It turns out this is a very easy task and here is my implementation demo:
template<typename T>
struct class_tag{};
auto createArray2=[]<typename T, size_t N>(class_tag<T>&&, integral_constant<size_t, N>&&){
return array<T, N>{};
};
auto ary5=createArray2(class_tag<string>{}, integral_constant<size_t, 5>{});
static_assert(is_same_v<decltype(ary5), array<string, 5>>);
So, I guess it solves my issue with help of all great comments below. Thank you for all!
template<auto x>
using constant_t = std::integral_constant<std::decay_t<decltype(x)>, x>;
template<auto x>
constexpr constant_t<x> constant{};
template<class T>
struct tag_t { using type=T; };
template<class T>
constexpr tag_t<T> tag{};
auto make_array=[]<auto N, class T>(constant_t<N>, tag_t<T>){
return std::array<T, N>{};
};
std::cout << make_array(constant<3>, tag<int>).size() << "\n";
Live example.
Here I use a tag dispatching technique. The tags carry the payload within their type, so can be passed by value and then the "payload" can be extracts as compile-time constants.
You can even make it a two-stage lambda if you want, where the template arguments are passed to an outer lambda, then the constants and types are used by an inner lambda:
auto make_array=[]<auto N, class T>(constant_t<N>, tag_t<T>) {
return [](auto&&...ts)requires (sizeof...(ts)==N && (std::is_convertible<decltype(ts), T>&&...))
{
return std::array<T,N>{ decltype(ts)(ts)... );
};
};
which is used like:
make_array(constant<3>, tag<int>)(1,2,3);
In older versions of C++, you can use auto arguments instead:
auto make_array=[](auto Size, auto Type) {
using T = typename decltype(Type)::type;
constexpr auto N = decltype(Size)::value;
return [](auto&&...ts)
{
return std::array<T,N>{ decltype(ts)(ts)... );
};
};
But constant<7> has to be replaced with
template<std::size_t N>
using ksize_t = std::integral_constant<std::size_t, N>;
template<std::size_t N>
constexpr ksize_t<N> ksize{};
because of the lack of auto non-type template parameters.
If you move template outside of lambda it will work very conveniently:
template<int N>
auto lambda = []{ return N; };
int main()
{
return lambda<5>();
}
https://gcc.godbolt.org/z/PsvYvW36Y
So, I actually have the answer: lambda parameter cannot be directly translated into template argument. Some trick of helper class is needed such as integral_constant, integer_sequence, class_tag etc. And because function parameter is not considered as compile-time constant, there is no way of directly using it as template argument. However, to solve my immediate requirement to avoid using lambda template argument call, it is workable by using these helper class. (see above comments and example code.)
Related
This code:
template<typename Arg, typename Ret>
Ret fun(std::function<Ret(Arg)> fun){
Arg x=0;
return fun(x);
};
auto f=[](int x){return x;};
fun(f); //compilation failed.
doesn't work. I want to get the argument and return type of lambda in fun.
I think the argument type has already known at comile time, why the compilier can't deduct it automaticall?
The problem here is that the lambda is not an std::function, so you're asking the compiler to do a deduction (find the type of Arg AND Ret) and a convertion i.e. convert the lambda to an std::function. The combination causes a conflict.
If you want to still use std::function as argument type for fun, then the easier thing to do is to make a utility that identifies what std::function to cast your callable to, e.g.:
#include <functional>
using namespace std;
template<typename T>
struct memfun_type
{
using type = void;
};
template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
using type = std::function<Ret(Args...)>;
};
template<typename F>
typename memfun_type<decltype(&std::decay_t<F>::operator())>::type
function_from(F&& func)
{
return std::forward<F>(func);
}
which you'd use as
fun(function_from(f)); // Auto-detect <Ret(Args...)> types.
Demo
After showing the mechanics of how auto-detection works, note that from C++17 onwards the CTAD feature does this for you. So in newer compilers this also works:
fun(std::function(f)); // Again no types specified.
Alternatively, you can make your f a bit more generic and use just the argument deduction, like:
template <class F>
auto fun(F &&fun)
{
int x=0;
return std::invoke(std::forward<F>(fun), x);
};
fun(f); // Call directly with your lambda
Demo
Using c++20 concepts, this version can be restricted to the argument and input function types that you want.
Suppose that we create two type_of functions that return std::type_identity, like:
template<auto VAR>
auto type_of() {
return std::type_identity<decltype(VAR)>{};
}
template<typename T>
auto type_of() {
return std::type_identity<T>{};
}
The way to get an actual type from std::type_identity seems a bit cumbersome:
// this works
// both i1 and i2 are ints
decltype(type_of<int>())::type i1;
decltype(type_of<int{}>())::type i2;
Is there a way to waive the need for decltype in above expressions, or to put it inside a reusable expression, to achieve something nicer like:
// can this work?
type_of<int>()::type i1;
type_of<int{}>()::type i2;
Or even better:
// can this work??
type_of_t<int> i1;
type_of_t<int{}> i2;
Note: specialization for type and non-type template parameter, which could have been a direction, doesn't work (cannot compile):
template<auto>
struct type_of;
template<typename T>
struct type_of<T> { // <== compilation error: type/value mismatch
using type = T;
};
template<auto VAR>
struct type_of<VAR> {
using type = decltype(VAR);
};
You can create a type alias. However you can't "overload" it. So my solution is to create two:
template <auto Var>
using type_of_var_t = decltype(type_of<Var>())::type;
template <class T>
using type_of_t = decltype(type_of<T>())::type;
auto test()
{
type_of_var_t<11> i1 = 24;
type_of_t<int> i2 = 17;
}
In C++, a template parameter must be a value, a type, or another template (which itself must fit within the declared template header). It must be exactly one of these.
If you want to do this:
the idea is to get something that is unaware on the caller side whether the template parameter is a type or a variable
The basic requirement for being able to do this is to write a template with a parameter that could be a value or a type.
That's not a thing C++ allows.
Template function overloading allows you to get away with something like that. But that only works because it isn't one template. It's two templates that are overloaded. Which one gets selected depends on the template arguments provided.
Template classes can't be overloaded. And template specialization cannot change the nature of the original template (like what its template parameters are). It can only allow you to reinterpret the template parameters of the original template parameters in order to provide an alternative implementation.
If you want this, you're going to have to wait until either C++ gets the ability to have a template parameter that could be anything or until C++ gets the ability to convert types into values and back (ie: reflection).
Getting the type from an std::type_identity object can be encapsulated into the following expresion:
template<auto x>
using type = typename decltype(x)::type;
This would allow to replace the cumbersome expressions:
decltype(type_of<int>())::type i1;
decltype(type_of<int{}>())::type i2;
With a more simple expression:
type<type_of<int>()> i1;
type<type_of<int{}>()> i2;
It still requires to go through two steps (type_of then type) as the first one shall be able to get a type or a variable, which is applicable only with function template overloading, then the function cannot return a type, so it returns an object that needs a template expression to extract the inner type.
Depending on what you want to do with the type, the code can become even simpler.
If all you want is to create an object of that type, you can forward the creation of the object into the function:
template<auto VAR, typename... Args>
auto create_type_of(Args&&... args) {
return decltype(VAR){std::forward<Args>(args)...};
}
template<typename T, typename... Args>
auto create_type_of(Args&&... args) {
return T{std::forward<Args>(args)...};
}
auto i1 = create_type_of<int>(7);
auto i2 = create_type_of<int{}>(7);
The generic case of creating a type from std::type_identity can work this way:
template<auto VAR>
constexpr auto type_of() {
return std::type_identity<decltype(VAR)>{};
}
template<typename T>
constexpr auto type_of() {
return std::type_identity<T>{};
}
template<typename T, typename... Args>
auto create(std::type_identity<T>, Args&&... args) {
return T{std::forward<Args>(args)...};
}
auto i1 = create(type_of<int>(), 7);
auto i2 = create(type_of<int{}>(), 7);
Note that the entire thing works only with variables that can be used as non-type template parameters. For a more generic approach that works without templates (but with a macro...), and thus can work for variables that cannot be template parameters, see this mind blowing neat answer!
By design, template arguments in C++ templates are either templates, types or values.
Within the template, you know which they are. All expressions within the template that are dependent on the template arguments are disambiguated using typename or template keywords (or context) so their category is known before arguments are substituted.
Now there are metaprogramming libraries that work with value-substitutes for all 3.
template<class T> struct type_tag_t {using type=T;};
template<class T> constexpr type_tag_t<T> tag={};
template<template<class...>class Z> struct template_z_t {
template<class...Ts>
using result = Z<Ts...>;
template<class...Ts>
constexpr result<Ts...> operator()( type_tag_t<Ts>... ) const { return {}; }
};
template<template<class...>class Z>
constexpr template_z_t<Z> template_z = {};
here templates are mapped to constexpr function objects. The template_z template lets you map type-templates over to this domain.
template<auto x>
using type = typename decltype(x)::type;
template<auto x>
constexpr std::integral_constant<std::decay_t<decltype(x)>, x> k = {};
So,
constexpr auto vector_z = template_z<std::vector>;
constexpr auto vector_tag = vector_z( tag<int>, tag<std::allocator<int>> );
then you can go back to the type:
type<vector_tag> v{1,2,3,4};
this probably isn't what you want.
You might be willing to check the proposal for Universal Template Parameters
The implication example quite match your use-case of specializing for both TTP and NTTP :
template <template auto>
struct X;
template <typename T>
struct X<T> {
// T is a type
using type = T;
};
template <auto val>
struct X<val> : std::integral_constant<decltype(val), val> {
// val is an NTTP
};
I'm making an entity-component system library utilizing template metaprogramming to evaluate signature bitset data at compile-time and allow for precise bitset size without using #define MAX_COMPONENTS some-number.
I'm using Boost Hana and have a function which should look like this:
template <auto T>
static constexpr Bitset signatureBitset = Bitset(
hana::fold(SignatureList[hana::integral_c<std::size_t, signatureID<T>>], 0,
[](auto l, auto r) {
return l | 1 << inferProperty<primitiveBit>(r);
}));
What it does is calculate constexpr Bitset for given signature. Signature is a hana::tuple_t of ECS component and tag types.
primitiveBit returns bit offset of template argument type component/tag. As hana::fold lambda doesn't provide type of current r, I can't simply call primitiveBit<RType> (RType is not defined).
Simplest possible solution would be to write a duplicate of every template "function" but as an actual constexpr function instead of static constexpr object but I'm trying to avoid that as writing 30+ duplicate function which all do
template <typename T>
static constexpr auto inferFunctionName(hana::basic_type<T> t) {
return functionName<T>;
}
seems dumb and will make everything harder to maintain. The above code also looks very simple and like it can be abstracted away using template function taking template constexpr object as a template parameter.
This is what I currently have:
template <template<typename> typename TReturn, typename T>
constexpr auto inferProperty(hana::basic_type<T> t) {
return TReturn<T>();
}
inferProperty<primitiveBit>(r) throws a compile error saying it doesn't match defined template signature.
Using template <template<typename T> typename TReturn, typename T> isn't an option due to T not being defined within lambdas.
Simple solution, as said by Jack C. in the comments, is to use decltype(r) inside lambda to get type from object instead of inferring type through template functions.
Which means propertyCheck<typename decltype(r)::type> works.
I have been searching through SO, and other forums looking for a way to determine the parameters and return type of a lambda, and then act on those parameters in order to do a type lookup on a repo of objects that have already been instantiated. The point is to create a way to do dependency injection on some arbitrarily defined lambda expression. For instance, if I have something like the following:
auto lambda = [] (MyObject o) -> string { return o.name(); };
I could determine the parameter types of the lambda, and lookup a corresponding object of type MyObject, and then call lambda passing that object "automagically".
So far, I've found ways to determine the lambdas parameter list types and return types by using the following templates:
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
enum { arity = sizeof...(Args) };
// arity is the number of arguments.
typedef ReturnType result_type;
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
// the i-th argument is equivalent to the i-th tuple element of a tuple
// composed of those arguments.
};
};
Which I found in this SO post (very neat).
Now, what I'd like to do, is implement some sort of compile time equivalent of the following:
// first get the type of the lambda using the above 'function_traits' template
typedef function_traits<decltype(lambda)> traits;
// now iterate over the traits and get the type of each argument, then print out the type name
for (size_t i = 0u; i < size_t(traits::arity); ++i)
{
// The point to focus on here is `traits::args<i>::type`
std::cout << typeid(traits::args<i>::type).name() << std::end;
}
What I've posted above is impossible. The issue in the code above is that i is not a constant, and is evaluated at run-time, as opposed to compile time (where the rest of this template magic is evaluated). I have tried a few different things to try to figure out a way to go about this (template recursion among them), but I haven't been able to find a solution that does exactly what I want.
So, the root of my question really is, how do you "iterate" over a template? I am new to TMP, and making the mental shift from run-time to compile-time logic has been challenging. If anyone has some suggestions for a newbie that would be great.
With C++14, you may do:
namespace detail
{
template <typename T, std::size_t ... Is>
void display(std::index_sequence<Is...>)
{
std::initializer_list<int>{((std::cout << typeid(typename T::template arg<Is>::type).name() << std::endl), 0)...};
}
}
template <typename T>
void display()
{
detail::display<T>(std::make_index_sequence<T::arity>());
}
And use it:
using traits = function_traits<decltype(lambda)>;
display<traits>();
Live example
If your stuck with C++11, there is many place to find implementation of make_index_sequence and index_sequence
As per my previous post, I learned that I cannot use a function parameter as an argument to a compile-time construct. This is because the parameter to function is expected at run-time, but the template argument is processed at compile-time.
Since I unfortunately cannot use constexpr on a parameter, I decided to use template argument. It works fine but with respect to looks I wouldn't say it's the best alternative:
#include <tuple>
template <class... Args>
struct type_list
{
std::tuple<Args...> var;
type_list(Args&&... args) : var(std::forward<Args>(args)...) {}
template <std::size_t N>
auto operator[](std::size_t)
-> typename std::tuple_element<N, std::tuple<Args...>>::type&&
{
return std::move(std::get<N>(var));
}
};
int main()
{
type_list<int, int, bool> list(2, 4, true);
int i = list.operator[]<0>(0); // How can I avoid this?
}
Is there some way I can avoid this? How can give a constant expression to a function while avoid the explicit operator syntax? Is it possible with macros?
You can add a class template that wraps a compile-time constant (or use this one http://www.boost.org/doc/libs/1_53_0/libs/mpl/doc/refmanual/int.html), make the parameter of the operator [] templated, and pass values of wrapped constants to the operator. The declaration of your operator changes to this:
template <typename T>
auto operator[](T) -> ...
Inside the operator replace N with T::value if you use boost MPL
Use of the operator changes to this:
int i = list[int_<0>()];