Invocation of C++20 template lambda gives parsing error [duplicate] - c++

Why does the first call not compile?
auto get1 = []<int B>() { return B; };
auto get2 = []<typename B>(B b) { return b; };
int main()
{
get1<5>(); // error: no match for operator<
get2(5); // ok
}
The reason I use this, is an expression repeated many times in code.
Of course I can use a real function template, but just I am curious WHY.

This is easier to understand if you consider what the equivalent class type looks like to your get1:
struct get1_t {
template <int B> operator()() const { return B; }
};
get1_t get1;
get1<5>(); // error
You're trying to provide an explicit template parameter to the call operator, but syntactically you're doing what looks like providing template parameters for get1 itself (i.e. as if get1 were a variable template). In order to provide the template parameter for the call operator, you have to do that directly:
get1.operator()<5>(); // ok
Or restructure the call operator to take something deducible:
template <int B> struct constant { };
get1(constant<5>{});
Or restructure the whole thing to actually be the variable template that it looks like it is:
template <int B>
auto get1 = [] { return B; };
Now, get1<5> is itself a lambda, that you're invoking. That is, rather than a lambda with a call operator template we have a variable template lambda that is itself not a template.

Related

C++ class template taking either type or non-type

I see a few similar questions, but they don't seem to get at this.
I can overload a function on a template:
template <typename T> void foo(); // Called as e.g., foo<int>();
template <std::size_t I> void foo(); // Called as e.g., foo<2>();
Is there a way to do something similar with a class, where I can have either MyClass<int> or MyClass<2>?
I can't see a way to do it. (My real goal is to have a static constexpr instance of an invokable that acts like std::get. Whereas std::get is templated on its "indexing" parameter and on the argument type, I'd like to make one that is invokable on its own, so myns::get<2> and myns::get<int> are both invokable and when invoked act like std::get<2>(tup) and std::get<int>(tup) respectively.
Naively you'd hope something like this would work, but the auto is a type:
template <auto IndOrType>
constexpr auto get = [](auto&& tup) {
return std::get<IndOrType>(std::forward<decltype(tup)>(tup));
};
I can make a getter function that returns a lambda, but then it's called with () as in myns::get<2>()(tup) or myns::get<int>()(tup).
You could specialize the class using the helper type std::integral_constant<int,N>. Though unfortunately this doesn't exactly allow the MyClass<2> syntax:
#include <type_traits>
template<typename T>
class MyClass
{
};
template<int N>
using ic = std::integral_constant<int,N>;
template<int N>
class MyClass<ic<N>>
{
};
int main()
{
MyClass<int> a;
MyClass<ic<2>> b;
}
https://godbolt.org/z/84xoE1Yd4

Calling lambda with non-parameter template argument

MSVC 2019 allow me to define a lambda like this, where the template argument is not used in the parameter list:
auto foo = []<bool B>() {
return B;
};
However, it gives syntax error when trying to call it like this?
foo<false>();
What is the correct way to call a lambda with a non-parameter template argument?
The template parameter is used with operator() of lambda.
(since C++20) If the lambda definition uses an explicit template parameter list, that template parameter list is used with operator().
You can specify the non-type template argument for operator(), call the lambda in an unnormal style as:
foo.operator()<false>();
foo is a function object. It has an operator(). The template on a lambda is on that operator, not on the object name itself.
foo<T> attempts to give the name foo a template argument T; that isn't valid here. foo<T>() gives the template argument to foo, then calls () on the result. Again, not what is going on here.
A template variable would work the way you want this to:
template<bool B>
auto foo = []() {
return B;
};
such variables only work in global scope, but here foo<true>() would work.
As a lambda is actually a compiler-generate class:
struct some_secret_name {
template<bool B>
auto operator()() const {
return B;
}
};
some_secret_name foo;
then the "right" way to call it is the ugly syntax:
foo.operator()<true>();
this, honestly, sucks.
You can get slightly better syntax like this:
template<class T> struct tag_t {using type=T;};
template<class T> constexpr tag_t<T> tag_v={};
template<auto v> using value_t = std::integral_constant<std::decay_t<decltype(v)>, v>;
template<auto v> constexpr value_t<v> value_v={};
then we can do
auto foo = []<bool B>(value_t<B>) {
return []{
return B;
};
};
now the syntax is:
foo(value_v<false>)();
which looks a bit less cludgy, if overly magical.
foo is now a lambda that makes lambdas, the outer lambda takes your template parameters as function arguments, and the inner lambda is the body.

Lambda functions with template parameters, not in function parameters

Why does the first call not compile?
auto get1 = []<int B>() { return B; };
auto get2 = []<typename B>(B b) { return b; };
int main()
{
get1<5>(); // error: no match for operator<
get2(5); // ok
}
The reason I use this, is an expression repeated many times in code.
Of course I can use a real function template, but just I am curious WHY.
This is easier to understand if you consider what the equivalent class type looks like to your get1:
struct get1_t {
template <int B> operator()() const { return B; }
};
get1_t get1;
get1<5>(); // error
You're trying to provide an explicit template parameter to the call operator, but syntactically you're doing what looks like providing template parameters for get1 itself (i.e. as if get1 were a variable template). In order to provide the template parameter for the call operator, you have to do that directly:
get1.operator()<5>(); // ok
Or restructure the call operator to take something deducible:
template <int B> struct constant { };
get1(constant<5>{});
Or restructure the whole thing to actually be the variable template that it looks like it is:
template <int B>
auto get1 = [] { return B; };
Now, get1<5> is itself a lambda, that you're invoking. That is, rather than a lambda with a call operator template we have a variable template lambda that is itself not a template.

Is it possible to use template with operator overload in C++?

Is it possible to use template together with operator overload (not using template together with the class, but only with the specific operator such as operator[]) in C++?
Here is an example (of course it can not be compiled pass).
class myClass
{
....
template<int i> auto operator[](std::string) -> std::tuple_element_t<t, types>
{
//some code here
}
...
}
int main()
{
myClass myObject;
....
auto a = myObject["rabbit"]<1>;
auto b = myObject["dog"]<2>;
...
}
Yes, it is possible, but the way you call it has to change. In order to specify the template parameter of operator[] you need to call it with member function syntax like
myObject.operator[]<1>("rabbit");
Which really isn't very nice to look at. Instead, you could just use a named member function like get and then use it like
class myClass
{
....
template<int i> auto get(std::string) -> std::tuple_element_t<t, types>
{
//some code here
}
...
}
auto a = myObject.get<1>("rabbit");

Part of code as template argument

We all know, what is template. Strongly speaking, it is a part of code which is checked for errors only when a copy of it was used and all the arguments where set.
We also know, that the arguments of template must be constant-value expressions. So we cant use variables as the arguments for the template.
But we can see that when template is compiled, the code responsible for it is like copied with the arguments pasted on formal parameters.
Can we use a part of a code as an argument of a template?
For example we have:
template<bool arg>
class foo
{
bool val;
public:
foo() : val(arg) {};
}
Everething is ok, thats works well as arg is an constant value.
But, I want't to use a static part of code, pasted to the template like this:
class foo
{
int a,b,c;
public:
foo() : a(0),b(0),c(0)
{};
foo(int an, int bn, int cn) : a(an),b(bn),c(cn)
{};
template<partOfCode cond>
bool foo_check()
{
if(cond) return true;
else return false;
};
};
int main(char* args, char** argv)
{
foo foovar;
foovar.foo_check<this->a==0>();
//or
foovar.foo_check<a==3>();
};
Of course I get the errors trying to do like this. But if really paste a part of argument code to the template on its place, there will be no any syntax errors at least.
Somebody can answer, that I can use define directive. But that will not help, as template and preprocessor are independent.
Is there a way to implement something like this?
Templates don't copy text like macros do, so you're:
trying to reference this in non-member function
trying to access inaccessible variable
trying to instantiate template with run-time value instead of compile-time constant
You'll have to pass a function:
template <typename FunctionToCall>
bool foo_check(FunctionToCall func)
{
return func(); // simplified
};
// this is how you call it with lambda function
foovar.foo_check([&]{ return foovar.get_a() == 0; }); // still have to provide an accessor, or make a friend function instead
The hell with the template, if you need just function for a condition, you can do
bool foo_check(std::function<bool()> const& func)
{
return func(); // at this point, isn't foo_check useless?
}