Is it possible to static_assert that a lambda is not generic? Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 00:00UTC (8:00pm US/Eastern) Data science time! April 2019 and salary with experience The Ask Question Wizard is Live!Can we get the type of a lambda argument?Is it possible to write a template to check for a function's existence?What is a lambda expression in C++11?Compiling with gcc fails if using lambda function for QObject::connect()c++11 - getting result_of, decltype, std::function and variadic templates working togetherTemplate Type Deduction with LambdasVariadic template method and std::function - compilation errorRecursively visiting an `std::variant` using lambdas and fixed-point combinatorsClang can't find template binary operator in fold expressionGenerating lambda from class templateGetting active value in std::visit without knowing which value is active
Dyck paths with extra diagonals from valleys (Laser construction)
Hangman Game with C++
In musical terms, what properties are varied by the human voice to produce different words / syllables?
AppleTVs create a chatty alternate WiFi network
Why are vacuum tubes still used in amateur radios?
Random body shuffle every night—can we still function?
Why can't I install Tomboy in Ubuntu Mate 19.04?
How many morphisms from 1 to 1+1 can there be?
Most bit efficient text communication method?
How can I prevent/balance waiting and turtling as a response to cooldown mechanics
Lagrange four-squares theorem --- deterministic complexity
How to write capital alpha?
Is CEO the "profession" with the most psychopaths?
How much damage would a cupful of neutron star matter do to the Earth?
Significance of Cersei's obsession with elephants?
How many time has Arya actually used Needle?
If Windows 7 doesn't support WSL, then what is "Subsystem for UNIX-based Applications"?
Is it possible to give , in economics, an example of a relation ( set of ordered pairs) that is not a function?
Central Vacuuming: Is it worth it, and how does it compare to normal vacuuming?
What is the home of the drow in Flanaess?
Would it be easier to apply for a UK visa if there is a host family to sponsor for you in going there?
Why is there Net Work Done on a Pressure/Volume Cycle?
What to do with repeated rejections for phd position
How were pictures turned from film to a big picture in a picture frame before digital scanning?
Is it possible to static_assert that a lambda is not generic?
Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 23, 2019 at 00:00UTC (8:00pm US/Eastern)
Data science time! April 2019 and salary with experience
The Ask Question Wizard is Live!Can we get the type of a lambda argument?Is it possible to write a template to check for a function's existence?What is a lambda expression in C++11?Compiling with gcc fails if using lambda function for QObject::connect()c++11 - getting result_of, decltype, std::function and variadic templates working togetherTemplate Type Deduction with LambdasVariadic template method and std::function - compilation errorRecursively visiting an `std::variant` using lambdas and fixed-point combinatorsClang can't find template binary operator in fold expressionGenerating lambda from class templateGetting active value in std::visit without knowing which value is active
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I implemented a Visit function (on a variant) that checks that the currently active type in the variant matches the function signature (more precisely the first argument). Based on this nice answer.
For example
#include <variant>
#include <string>
#include <iostream>
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
std::variant<int, std::string> data="abc";
template <typename V>
void Visit(V v)
using Arg1 = typename std::remove_const_t<std::remove_reference_t<first_argument<V>>>;//... TMP magic to get 1st argument of visitor + remove cvr, see Q 43526647
if (! std::holds_alternative<Arg1>(data))
std::cerr<< "alternative mismatchn";
return;
v(std::get<Arg1>(data));
int main()
Visit([](const int& i)std::cout << i << "n"; );
Visit([](const std::string& s)std::cout << s << "n"; );
// Visit([](auto& x)); ugly kabooom
This works, but it explodes with a user unfriendly compile time error when users passes a generic (e.g. [](auto&)
) lambda. Is there a way to detect this and give nice static_assert()
about it?
Would also be nice if it worked with function templates as well, not just with lambdas.
Note that I do not know what possible lambdas do, so I can not do some clever stuff with Dummy types since lambdas may invoke arbitrary functions on types.
In other words I can not try to call lambda in 2 std::void_t
tests on int
and std::string
and if it works assume it is generic because they might try to call .BlaLol()
on int
and string
.
c++ c++17 variadic-templates template-meta-programming generic-lambda
add a comment |
I implemented a Visit function (on a variant) that checks that the currently active type in the variant matches the function signature (more precisely the first argument). Based on this nice answer.
For example
#include <variant>
#include <string>
#include <iostream>
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
std::variant<int, std::string> data="abc";
template <typename V>
void Visit(V v)
using Arg1 = typename std::remove_const_t<std::remove_reference_t<first_argument<V>>>;//... TMP magic to get 1st argument of visitor + remove cvr, see Q 43526647
if (! std::holds_alternative<Arg1>(data))
std::cerr<< "alternative mismatchn";
return;
v(std::get<Arg1>(data));
int main()
Visit([](const int& i)std::cout << i << "n"; );
Visit([](const std::string& s)std::cout << s << "n"; );
// Visit([](auto& x)); ugly kabooom
This works, but it explodes with a user unfriendly compile time error when users passes a generic (e.g. [](auto&)
) lambda. Is there a way to detect this and give nice static_assert()
about it?
Would also be nice if it worked with function templates as well, not just with lambdas.
Note that I do not know what possible lambdas do, so I can not do some clever stuff with Dummy types since lambdas may invoke arbitrary functions on types.
In other words I can not try to call lambda in 2 std::void_t
tests on int
and std::string
and if it works assume it is generic because they might try to call .BlaLol()
on int
and string
.
c++ c++17 variadic-templates template-meta-programming generic-lambda
1
What if the functor has an overloadedoperator()
? Visiting is also very commonly performed with overloaded functors (see example 4 here), do those have to be forbidden (or have to work)?
– Max Langhof
Apr 3 at 7:35
I think that is too hard to handle, but if it can be done that would be nice... so it is optional, not required.
– NoSenseEtAl
Apr 3 at 8:16
add a comment |
I implemented a Visit function (on a variant) that checks that the currently active type in the variant matches the function signature (more precisely the first argument). Based on this nice answer.
For example
#include <variant>
#include <string>
#include <iostream>
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
std::variant<int, std::string> data="abc";
template <typename V>
void Visit(V v)
using Arg1 = typename std::remove_const_t<std::remove_reference_t<first_argument<V>>>;//... TMP magic to get 1st argument of visitor + remove cvr, see Q 43526647
if (! std::holds_alternative<Arg1>(data))
std::cerr<< "alternative mismatchn";
return;
v(std::get<Arg1>(data));
int main()
Visit([](const int& i)std::cout << i << "n"; );
Visit([](const std::string& s)std::cout << s << "n"; );
// Visit([](auto& x)); ugly kabooom
This works, but it explodes with a user unfriendly compile time error when users passes a generic (e.g. [](auto&)
) lambda. Is there a way to detect this and give nice static_assert()
about it?
Would also be nice if it worked with function templates as well, not just with lambdas.
Note that I do not know what possible lambdas do, so I can not do some clever stuff with Dummy types since lambdas may invoke arbitrary functions on types.
In other words I can not try to call lambda in 2 std::void_t
tests on int
and std::string
and if it works assume it is generic because they might try to call .BlaLol()
on int
and string
.
c++ c++17 variadic-templates template-meta-programming generic-lambda
I implemented a Visit function (on a variant) that checks that the currently active type in the variant matches the function signature (more precisely the first argument). Based on this nice answer.
For example
#include <variant>
#include <string>
#include <iostream>
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
std::variant<int, std::string> data="abc";
template <typename V>
void Visit(V v)
using Arg1 = typename std::remove_const_t<std::remove_reference_t<first_argument<V>>>;//... TMP magic to get 1st argument of visitor + remove cvr, see Q 43526647
if (! std::holds_alternative<Arg1>(data))
std::cerr<< "alternative mismatchn";
return;
v(std::get<Arg1>(data));
int main()
Visit([](const int& i)std::cout << i << "n"; );
Visit([](const std::string& s)std::cout << s << "n"; );
// Visit([](auto& x)); ugly kabooom
This works, but it explodes with a user unfriendly compile time error when users passes a generic (e.g. [](auto&)
) lambda. Is there a way to detect this and give nice static_assert()
about it?
Would also be nice if it worked with function templates as well, not just with lambdas.
Note that I do not know what possible lambdas do, so I can not do some clever stuff with Dummy types since lambdas may invoke arbitrary functions on types.
In other words I can not try to call lambda in 2 std::void_t
tests on int
and std::string
and if it works assume it is generic because they might try to call .BlaLol()
on int
and string
.
c++ c++17 variadic-templates template-meta-programming generic-lambda
c++ c++17 variadic-templates template-meta-programming generic-lambda
edited Apr 3 at 8:16
max66
39.6k74575
39.6k74575
asked Apr 3 at 6:21
NoSenseEtAlNoSenseEtAl
7,7741678185
7,7741678185
1
What if the functor has an overloadedoperator()
? Visiting is also very commonly performed with overloaded functors (see example 4 here), do those have to be forbidden (or have to work)?
– Max Langhof
Apr 3 at 7:35
I think that is too hard to handle, but if it can be done that would be nice... so it is optional, not required.
– NoSenseEtAl
Apr 3 at 8:16
add a comment |
1
What if the functor has an overloadedoperator()
? Visiting is also very commonly performed with overloaded functors (see example 4 here), do those have to be forbidden (or have to work)?
– Max Langhof
Apr 3 at 7:35
I think that is too hard to handle, but if it can be done that would be nice... so it is optional, not required.
– NoSenseEtAl
Apr 3 at 8:16
1
1
What if the functor has an overloaded
operator()
? Visiting is also very commonly performed with overloaded functors (see example 4 here), do those have to be forbidden (or have to work)?– Max Langhof
Apr 3 at 7:35
What if the functor has an overloaded
operator()
? Visiting is also very commonly performed with overloaded functors (see example 4 here), do those have to be forbidden (or have to work)?– Max Langhof
Apr 3 at 7:35
I think that is too hard to handle, but if it can be done that would be nice... so it is optional, not required.
– NoSenseEtAl
Apr 3 at 8:16
I think that is too hard to handle, but if it can be done that would be nice... so it is optional, not required.
– NoSenseEtAl
Apr 3 at 8:16
add a comment |
3 Answers
3
active
oldest
votes
Is there a way to detect this and give nice static_assert about it?
I suppose you can use SFINAE over operator()
type.
Follows an example
#include <type_traits>
template <typename T>
constexpr auto foo (T const &)
-> decltype( &T::operator(), bool )
return true;
constexpr bool foo (...)
return false;
int main()
auto l1 = [](int) return 0; ;
auto l2 = [](auto) return 0; ;
static_assert( foo(l1), "!" );
static_assert( ! foo(l2), "!" );
Instead of a bool
, you can return std::true_type
(from foo()
first version) or std::false_type
(from second version) if you want to use it through decltype()
.
Would also be nice if it worked with function templates as well, not just with lambdas.
I don't think it's possible in a so simple way: a lambda (also a generic lambda) is an object; a template function isn't an object but a set of objects. You can pass an object to a function, not a set of objects.
But the preceding solution should works also for classes/structs with operator()
s: when there is a single, non template, operator()
, you should get 1
from foo()
; otherwise (no operator()
, more than one operator()
, template operator()
), foo()
should return 0
.
2
Trying to take the address ofoperator()
was my initial idea as well (hence the comment) but then I somehow got lost in SFINAE on actually calling it. Anyway, here are some extra test cases involving overloaded functors: godbolt.org/z/M319jo
– Max Langhof
Apr 3 at 8:32
add a comment |
Yet another simpler option:
#include <type_traits>
...
template <typename V>
void Visit(V v)
class Auto ;
static_assert(!std::is_invocable<V, Auto&>::value);
static_assert(!std::is_invocable<V, Auto*>::value);
...
The Auto
class is just an invented type impossible to occur in the V
parameters. If V
accepts Auto
as an argument it must be a generic.
I tested in coliru and I can confirm the solution covers these cases:
Visit([](auto x)); // nice static assert
Visit([](auto *x)); // nice static assert
Visit([](auto &x)); // nice static assert
Visit([](auto &&x)); // nice static assert
I'm not sure if that would cover all the possible lambdas that you don't know which are :)
Nice idea ! You may ensure that "Auto" is unique like that :auto a_lambda = [](); using Auto= decltype(a_lambda);
– Martin Morterol
Apr 3 at 9:58
@Martinm This seems to be the idiomatic way but does it actually have an advantage over the code in this answer?
– Konrad Rudolph
Apr 3 at 10:07
Well, I am not sure what happens in the case where an "Auto" class already define somewhere else. In meta-programming context I prefer to be sure that my type cannot be in conflict in some obscure case.
– Martin Morterol
Apr 3 at 10:19
4
This gives both false positives (e.g.Visit([](std::any));
) and false negatives (Visit([](int, auto));
orVisit([](auto*));
)
– Barry
Apr 3 at 11:47
Visit([](int, auto))
is not a valid case because ofv(std::get<Arg1>(data));
andVisit([](auto*));
is fixed now. I'm not sure ifVisit([](std::any))
is one of the cases to be avoided as the question isn't clear enough.
– olivecoder
Apr 3 at 12:09
|
show 4 more comments
#include <variant>
#include <string>
#include <iostream>
template <class U, typename T = void>
struct can_be_checked : public std::false_type ;
template <typename U>
struct can_be_checked<U, std::enable_if_t< std::is_function<U>::value > > : public std::true_type;
template <typename U>
struct can_be_checked<U, std::void_t<decltype(&U::operator())>> : public std::true_type;
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
std::variant<int, std::string> data="abc";
template <typename V>
void Visit(V v)
if constexpr ( can_be_checked<std::remove_pointer_t<decltype(v)>>::value )
using Arg1 = typename std::remove_const_t<std::remove_reference_t<first_argument<V>>>;//... TMP magic to get 1st argument of visitor + remove cvr, see Q 43526647
if (! std::holds_alternative<Arg1>(data))
std::cerr<< "alternative mismatchn";
return;
v(std::get<Arg1>(data));
else
std::cout << "it's a template / auto lambda " << std::endl;
template <class T>
void foo(const T& t)
std::cout <<t << " foo n";
void fooi(const int& t)
std::cout <<t << " fooi " << std::endl;
int main()
Visit([](const int& i)std::cout << i << std::endl; );
Visit([](const std::string& s)std::cout << s << std::endl; );
Visit([](auto& x)std::cout <<x << std::endl;); // it's a template / auto lambda*/
Visit(foo<int>);
Visit<decltype(fooi)>(fooi);
Visit(fooi);
// Visit(foo); // => fail ugly
I don't know if it's you want, but you can, with that static_assert if an auto lambda is passed as parameter.
I think it's not possible to do the same for template function, but not sure.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55488333%2fis-it-possible-to-static-assert-that-a-lambda-is-not-generic%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Is there a way to detect this and give nice static_assert about it?
I suppose you can use SFINAE over operator()
type.
Follows an example
#include <type_traits>
template <typename T>
constexpr auto foo (T const &)
-> decltype( &T::operator(), bool )
return true;
constexpr bool foo (...)
return false;
int main()
auto l1 = [](int) return 0; ;
auto l2 = [](auto) return 0; ;
static_assert( foo(l1), "!" );
static_assert( ! foo(l2), "!" );
Instead of a bool
, you can return std::true_type
(from foo()
first version) or std::false_type
(from second version) if you want to use it through decltype()
.
Would also be nice if it worked with function templates as well, not just with lambdas.
I don't think it's possible in a so simple way: a lambda (also a generic lambda) is an object; a template function isn't an object but a set of objects. You can pass an object to a function, not a set of objects.
But the preceding solution should works also for classes/structs with operator()
s: when there is a single, non template, operator()
, you should get 1
from foo()
; otherwise (no operator()
, more than one operator()
, template operator()
), foo()
should return 0
.
2
Trying to take the address ofoperator()
was my initial idea as well (hence the comment) but then I somehow got lost in SFINAE on actually calling it. Anyway, here are some extra test cases involving overloaded functors: godbolt.org/z/M319jo
– Max Langhof
Apr 3 at 8:32
add a comment |
Is there a way to detect this and give nice static_assert about it?
I suppose you can use SFINAE over operator()
type.
Follows an example
#include <type_traits>
template <typename T>
constexpr auto foo (T const &)
-> decltype( &T::operator(), bool )
return true;
constexpr bool foo (...)
return false;
int main()
auto l1 = [](int) return 0; ;
auto l2 = [](auto) return 0; ;
static_assert( foo(l1), "!" );
static_assert( ! foo(l2), "!" );
Instead of a bool
, you can return std::true_type
(from foo()
first version) or std::false_type
(from second version) if you want to use it through decltype()
.
Would also be nice if it worked with function templates as well, not just with lambdas.
I don't think it's possible in a so simple way: a lambda (also a generic lambda) is an object; a template function isn't an object but a set of objects. You can pass an object to a function, not a set of objects.
But the preceding solution should works also for classes/structs with operator()
s: when there is a single, non template, operator()
, you should get 1
from foo()
; otherwise (no operator()
, more than one operator()
, template operator()
), foo()
should return 0
.
2
Trying to take the address ofoperator()
was my initial idea as well (hence the comment) but then I somehow got lost in SFINAE on actually calling it. Anyway, here are some extra test cases involving overloaded functors: godbolt.org/z/M319jo
– Max Langhof
Apr 3 at 8:32
add a comment |
Is there a way to detect this and give nice static_assert about it?
I suppose you can use SFINAE over operator()
type.
Follows an example
#include <type_traits>
template <typename T>
constexpr auto foo (T const &)
-> decltype( &T::operator(), bool )
return true;
constexpr bool foo (...)
return false;
int main()
auto l1 = [](int) return 0; ;
auto l2 = [](auto) return 0; ;
static_assert( foo(l1), "!" );
static_assert( ! foo(l2), "!" );
Instead of a bool
, you can return std::true_type
(from foo()
first version) or std::false_type
(from second version) if you want to use it through decltype()
.
Would also be nice if it worked with function templates as well, not just with lambdas.
I don't think it's possible in a so simple way: a lambda (also a generic lambda) is an object; a template function isn't an object but a set of objects. You can pass an object to a function, not a set of objects.
But the preceding solution should works also for classes/structs with operator()
s: when there is a single, non template, operator()
, you should get 1
from foo()
; otherwise (no operator()
, more than one operator()
, template operator()
), foo()
should return 0
.
Is there a way to detect this and give nice static_assert about it?
I suppose you can use SFINAE over operator()
type.
Follows an example
#include <type_traits>
template <typename T>
constexpr auto foo (T const &)
-> decltype( &T::operator(), bool )
return true;
constexpr bool foo (...)
return false;
int main()
auto l1 = [](int) return 0; ;
auto l2 = [](auto) return 0; ;
static_assert( foo(l1), "!" );
static_assert( ! foo(l2), "!" );
Instead of a bool
, you can return std::true_type
(from foo()
first version) or std::false_type
(from second version) if you want to use it through decltype()
.
Would also be nice if it worked with function templates as well, not just with lambdas.
I don't think it's possible in a so simple way: a lambda (also a generic lambda) is an object; a template function isn't an object but a set of objects. You can pass an object to a function, not a set of objects.
But the preceding solution should works also for classes/structs with operator()
s: when there is a single, non template, operator()
, you should get 1
from foo()
; otherwise (no operator()
, more than one operator()
, template operator()
), foo()
should return 0
.
edited Apr 3 at 11:43
answered Apr 3 at 8:06
max66max66
39.6k74575
39.6k74575
2
Trying to take the address ofoperator()
was my initial idea as well (hence the comment) but then I somehow got lost in SFINAE on actually calling it. Anyway, here are some extra test cases involving overloaded functors: godbolt.org/z/M319jo
– Max Langhof
Apr 3 at 8:32
add a comment |
2
Trying to take the address ofoperator()
was my initial idea as well (hence the comment) but then I somehow got lost in SFINAE on actually calling it. Anyway, here are some extra test cases involving overloaded functors: godbolt.org/z/M319jo
– Max Langhof
Apr 3 at 8:32
2
2
Trying to take the address of
operator()
was my initial idea as well (hence the comment) but then I somehow got lost in SFINAE on actually calling it. Anyway, here are some extra test cases involving overloaded functors: godbolt.org/z/M319jo– Max Langhof
Apr 3 at 8:32
Trying to take the address of
operator()
was my initial idea as well (hence the comment) but then I somehow got lost in SFINAE on actually calling it. Anyway, here are some extra test cases involving overloaded functors: godbolt.org/z/M319jo– Max Langhof
Apr 3 at 8:32
add a comment |
Yet another simpler option:
#include <type_traits>
...
template <typename V>
void Visit(V v)
class Auto ;
static_assert(!std::is_invocable<V, Auto&>::value);
static_assert(!std::is_invocable<V, Auto*>::value);
...
The Auto
class is just an invented type impossible to occur in the V
parameters. If V
accepts Auto
as an argument it must be a generic.
I tested in coliru and I can confirm the solution covers these cases:
Visit([](auto x)); // nice static assert
Visit([](auto *x)); // nice static assert
Visit([](auto &x)); // nice static assert
Visit([](auto &&x)); // nice static assert
I'm not sure if that would cover all the possible lambdas that you don't know which are :)
Nice idea ! You may ensure that "Auto" is unique like that :auto a_lambda = [](); using Auto= decltype(a_lambda);
– Martin Morterol
Apr 3 at 9:58
@Martinm This seems to be the idiomatic way but does it actually have an advantage over the code in this answer?
– Konrad Rudolph
Apr 3 at 10:07
Well, I am not sure what happens in the case where an "Auto" class already define somewhere else. In meta-programming context I prefer to be sure that my type cannot be in conflict in some obscure case.
– Martin Morterol
Apr 3 at 10:19
4
This gives both false positives (e.g.Visit([](std::any));
) and false negatives (Visit([](int, auto));
orVisit([](auto*));
)
– Barry
Apr 3 at 11:47
Visit([](int, auto))
is not a valid case because ofv(std::get<Arg1>(data));
andVisit([](auto*));
is fixed now. I'm not sure ifVisit([](std::any))
is one of the cases to be avoided as the question isn't clear enough.
– olivecoder
Apr 3 at 12:09
|
show 4 more comments
Yet another simpler option:
#include <type_traits>
...
template <typename V>
void Visit(V v)
class Auto ;
static_assert(!std::is_invocable<V, Auto&>::value);
static_assert(!std::is_invocable<V, Auto*>::value);
...
The Auto
class is just an invented type impossible to occur in the V
parameters. If V
accepts Auto
as an argument it must be a generic.
I tested in coliru and I can confirm the solution covers these cases:
Visit([](auto x)); // nice static assert
Visit([](auto *x)); // nice static assert
Visit([](auto &x)); // nice static assert
Visit([](auto &&x)); // nice static assert
I'm not sure if that would cover all the possible lambdas that you don't know which are :)
Nice idea ! You may ensure that "Auto" is unique like that :auto a_lambda = [](); using Auto= decltype(a_lambda);
– Martin Morterol
Apr 3 at 9:58
@Martinm This seems to be the idiomatic way but does it actually have an advantage over the code in this answer?
– Konrad Rudolph
Apr 3 at 10:07
Well, I am not sure what happens in the case where an "Auto" class already define somewhere else. In meta-programming context I prefer to be sure that my type cannot be in conflict in some obscure case.
– Martin Morterol
Apr 3 at 10:19
4
This gives both false positives (e.g.Visit([](std::any));
) and false negatives (Visit([](int, auto));
orVisit([](auto*));
)
– Barry
Apr 3 at 11:47
Visit([](int, auto))
is not a valid case because ofv(std::get<Arg1>(data));
andVisit([](auto*));
is fixed now. I'm not sure ifVisit([](std::any))
is one of the cases to be avoided as the question isn't clear enough.
– olivecoder
Apr 3 at 12:09
|
show 4 more comments
Yet another simpler option:
#include <type_traits>
...
template <typename V>
void Visit(V v)
class Auto ;
static_assert(!std::is_invocable<V, Auto&>::value);
static_assert(!std::is_invocable<V, Auto*>::value);
...
The Auto
class is just an invented type impossible to occur in the V
parameters. If V
accepts Auto
as an argument it must be a generic.
I tested in coliru and I can confirm the solution covers these cases:
Visit([](auto x)); // nice static assert
Visit([](auto *x)); // nice static assert
Visit([](auto &x)); // nice static assert
Visit([](auto &&x)); // nice static assert
I'm not sure if that would cover all the possible lambdas that you don't know which are :)
Yet another simpler option:
#include <type_traits>
...
template <typename V>
void Visit(V v)
class Auto ;
static_assert(!std::is_invocable<V, Auto&>::value);
static_assert(!std::is_invocable<V, Auto*>::value);
...
The Auto
class is just an invented type impossible to occur in the V
parameters. If V
accepts Auto
as an argument it must be a generic.
I tested in coliru and I can confirm the solution covers these cases:
Visit([](auto x)); // nice static assert
Visit([](auto *x)); // nice static assert
Visit([](auto &x)); // nice static assert
Visit([](auto &&x)); // nice static assert
I'm not sure if that would cover all the possible lambdas that you don't know which are :)
edited Apr 3 at 14:05
answered Apr 3 at 8:56
olivecoderolivecoder
2,0881217
2,0881217
Nice idea ! You may ensure that "Auto" is unique like that :auto a_lambda = [](); using Auto= decltype(a_lambda);
– Martin Morterol
Apr 3 at 9:58
@Martinm This seems to be the idiomatic way but does it actually have an advantage over the code in this answer?
– Konrad Rudolph
Apr 3 at 10:07
Well, I am not sure what happens in the case where an "Auto" class already define somewhere else. In meta-programming context I prefer to be sure that my type cannot be in conflict in some obscure case.
– Martin Morterol
Apr 3 at 10:19
4
This gives both false positives (e.g.Visit([](std::any));
) and false negatives (Visit([](int, auto));
orVisit([](auto*));
)
– Barry
Apr 3 at 11:47
Visit([](int, auto))
is not a valid case because ofv(std::get<Arg1>(data));
andVisit([](auto*));
is fixed now. I'm not sure ifVisit([](std::any))
is one of the cases to be avoided as the question isn't clear enough.
– olivecoder
Apr 3 at 12:09
|
show 4 more comments
Nice idea ! You may ensure that "Auto" is unique like that :auto a_lambda = [](); using Auto= decltype(a_lambda);
– Martin Morterol
Apr 3 at 9:58
@Martinm This seems to be the idiomatic way but does it actually have an advantage over the code in this answer?
– Konrad Rudolph
Apr 3 at 10:07
Well, I am not sure what happens in the case where an "Auto" class already define somewhere else. In meta-programming context I prefer to be sure that my type cannot be in conflict in some obscure case.
– Martin Morterol
Apr 3 at 10:19
4
This gives both false positives (e.g.Visit([](std::any));
) and false negatives (Visit([](int, auto));
orVisit([](auto*));
)
– Barry
Apr 3 at 11:47
Visit([](int, auto))
is not a valid case because ofv(std::get<Arg1>(data));
andVisit([](auto*));
is fixed now. I'm not sure ifVisit([](std::any))
is one of the cases to be avoided as the question isn't clear enough.
– olivecoder
Apr 3 at 12:09
Nice idea ! You may ensure that "Auto" is unique like that :
auto a_lambda = [](); using Auto= decltype(a_lambda);
– Martin Morterol
Apr 3 at 9:58
Nice idea ! You may ensure that "Auto" is unique like that :
auto a_lambda = [](); using Auto= decltype(a_lambda);
– Martin Morterol
Apr 3 at 9:58
@Martinm This seems to be the idiomatic way but does it actually have an advantage over the code in this answer?
– Konrad Rudolph
Apr 3 at 10:07
@Martinm This seems to be the idiomatic way but does it actually have an advantage over the code in this answer?
– Konrad Rudolph
Apr 3 at 10:07
Well, I am not sure what happens in the case where an "Auto" class already define somewhere else. In meta-programming context I prefer to be sure that my type cannot be in conflict in some obscure case.
– Martin Morterol
Apr 3 at 10:19
Well, I am not sure what happens in the case where an "Auto" class already define somewhere else. In meta-programming context I prefer to be sure that my type cannot be in conflict in some obscure case.
– Martin Morterol
Apr 3 at 10:19
4
4
This gives both false positives (e.g.
Visit([](std::any));
) and false negatives (Visit([](int, auto));
or Visit([](auto*));
)– Barry
Apr 3 at 11:47
This gives both false positives (e.g.
Visit([](std::any));
) and false negatives (Visit([](int, auto));
or Visit([](auto*));
)– Barry
Apr 3 at 11:47
Visit([](int, auto))
is not a valid case because of v(std::get<Arg1>(data));
and Visit([](auto*));
is fixed now. I'm not sure if Visit([](std::any))
is one of the cases to be avoided as the question isn't clear enough.– olivecoder
Apr 3 at 12:09
Visit([](int, auto))
is not a valid case because of v(std::get<Arg1>(data));
and Visit([](auto*));
is fixed now. I'm not sure if Visit([](std::any))
is one of the cases to be avoided as the question isn't clear enough.– olivecoder
Apr 3 at 12:09
|
show 4 more comments
#include <variant>
#include <string>
#include <iostream>
template <class U, typename T = void>
struct can_be_checked : public std::false_type ;
template <typename U>
struct can_be_checked<U, std::enable_if_t< std::is_function<U>::value > > : public std::true_type;
template <typename U>
struct can_be_checked<U, std::void_t<decltype(&U::operator())>> : public std::true_type;
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
std::variant<int, std::string> data="abc";
template <typename V>
void Visit(V v)
if constexpr ( can_be_checked<std::remove_pointer_t<decltype(v)>>::value )
using Arg1 = typename std::remove_const_t<std::remove_reference_t<first_argument<V>>>;//... TMP magic to get 1st argument of visitor + remove cvr, see Q 43526647
if (! std::holds_alternative<Arg1>(data))
std::cerr<< "alternative mismatchn";
return;
v(std::get<Arg1>(data));
else
std::cout << "it's a template / auto lambda " << std::endl;
template <class T>
void foo(const T& t)
std::cout <<t << " foo n";
void fooi(const int& t)
std::cout <<t << " fooi " << std::endl;
int main()
Visit([](const int& i)std::cout << i << std::endl; );
Visit([](const std::string& s)std::cout << s << std::endl; );
Visit([](auto& x)std::cout <<x << std::endl;); // it's a template / auto lambda*/
Visit(foo<int>);
Visit<decltype(fooi)>(fooi);
Visit(fooi);
// Visit(foo); // => fail ugly
I don't know if it's you want, but you can, with that static_assert if an auto lambda is passed as parameter.
I think it's not possible to do the same for template function, but not sure.
add a comment |
#include <variant>
#include <string>
#include <iostream>
template <class U, typename T = void>
struct can_be_checked : public std::false_type ;
template <typename U>
struct can_be_checked<U, std::enable_if_t< std::is_function<U>::value > > : public std::true_type;
template <typename U>
struct can_be_checked<U, std::void_t<decltype(&U::operator())>> : public std::true_type;
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
std::variant<int, std::string> data="abc";
template <typename V>
void Visit(V v)
if constexpr ( can_be_checked<std::remove_pointer_t<decltype(v)>>::value )
using Arg1 = typename std::remove_const_t<std::remove_reference_t<first_argument<V>>>;//... TMP magic to get 1st argument of visitor + remove cvr, see Q 43526647
if (! std::holds_alternative<Arg1>(data))
std::cerr<< "alternative mismatchn";
return;
v(std::get<Arg1>(data));
else
std::cout << "it's a template / auto lambda " << std::endl;
template <class T>
void foo(const T& t)
std::cout <<t << " foo n";
void fooi(const int& t)
std::cout <<t << " fooi " << std::endl;
int main()
Visit([](const int& i)std::cout << i << std::endl; );
Visit([](const std::string& s)std::cout << s << std::endl; );
Visit([](auto& x)std::cout <<x << std::endl;); // it's a template / auto lambda*/
Visit(foo<int>);
Visit<decltype(fooi)>(fooi);
Visit(fooi);
// Visit(foo); // => fail ugly
I don't know if it's you want, but you can, with that static_assert if an auto lambda is passed as parameter.
I think it's not possible to do the same for template function, but not sure.
add a comment |
#include <variant>
#include <string>
#include <iostream>
template <class U, typename T = void>
struct can_be_checked : public std::false_type ;
template <typename U>
struct can_be_checked<U, std::enable_if_t< std::is_function<U>::value > > : public std::true_type;
template <typename U>
struct can_be_checked<U, std::void_t<decltype(&U::operator())>> : public std::true_type;
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
std::variant<int, std::string> data="abc";
template <typename V>
void Visit(V v)
if constexpr ( can_be_checked<std::remove_pointer_t<decltype(v)>>::value )
using Arg1 = typename std::remove_const_t<std::remove_reference_t<first_argument<V>>>;//... TMP magic to get 1st argument of visitor + remove cvr, see Q 43526647
if (! std::holds_alternative<Arg1>(data))
std::cerr<< "alternative mismatchn";
return;
v(std::get<Arg1>(data));
else
std::cout << "it's a template / auto lambda " << std::endl;
template <class T>
void foo(const T& t)
std::cout <<t << " foo n";
void fooi(const int& t)
std::cout <<t << " fooi " << std::endl;
int main()
Visit([](const int& i)std::cout << i << std::endl; );
Visit([](const std::string& s)std::cout << s << std::endl; );
Visit([](auto& x)std::cout <<x << std::endl;); // it's a template / auto lambda*/
Visit(foo<int>);
Visit<decltype(fooi)>(fooi);
Visit(fooi);
// Visit(foo); // => fail ugly
I don't know if it's you want, but you can, with that static_assert if an auto lambda is passed as parameter.
I think it's not possible to do the same for template function, but not sure.
#include <variant>
#include <string>
#include <iostream>
template <class U, typename T = void>
struct can_be_checked : public std::false_type ;
template <typename U>
struct can_be_checked<U, std::enable_if_t< std::is_function<U>::value > > : public std::true_type;
template <typename U>
struct can_be_checked<U, std::void_t<decltype(&U::operator())>> : public std::true_type;
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
std::variant<int, std::string> data="abc";
template <typename V>
void Visit(V v)
if constexpr ( can_be_checked<std::remove_pointer_t<decltype(v)>>::value )
using Arg1 = typename std::remove_const_t<std::remove_reference_t<first_argument<V>>>;//... TMP magic to get 1st argument of visitor + remove cvr, see Q 43526647
if (! std::holds_alternative<Arg1>(data))
std::cerr<< "alternative mismatchn";
return;
v(std::get<Arg1>(data));
else
std::cout << "it's a template / auto lambda " << std::endl;
template <class T>
void foo(const T& t)
std::cout <<t << " foo n";
void fooi(const int& t)
std::cout <<t << " fooi " << std::endl;
int main()
Visit([](const int& i)std::cout << i << std::endl; );
Visit([](const std::string& s)std::cout << s << std::endl; );
Visit([](auto& x)std::cout <<x << std::endl;); // it's a template / auto lambda*/
Visit(foo<int>);
Visit<decltype(fooi)>(fooi);
Visit(fooi);
// Visit(foo); // => fail ugly
I don't know if it's you want, but you can, with that static_assert if an auto lambda is passed as parameter.
I think it's not possible to do the same for template function, but not sure.
answered Apr 3 at 8:12
Martin MorterolMartin Morterol
31316
31316
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55488333%2fis-it-possible-to-static-assert-that-a-lambda-is-not-generic%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
What if the functor has an overloaded
operator()
? Visiting is also very commonly performed with overloaded functors (see example 4 here), do those have to be forbidden (or have to work)?– Max Langhof
Apr 3 at 7:35
I think that is too hard to handle, but if it can be done that would be nice... so it is optional, not required.
– NoSenseEtAl
Apr 3 at 8:16