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;








10















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.










share|improve this question



















  • 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

















10















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.










share|improve this question



















  • 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













10












10








10


2






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.










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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












  • 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







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












3 Answers
3






active

oldest

votes


















11















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.






share|improve this answer




















  • 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



















4














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 :)






share|improve this answer

























  • 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)); 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



















3














#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.






share|improve this answer























    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
    );



    );













    draft saved

    draft discarded


















    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









    11















    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.






    share|improve this answer




















    • 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
















    11















    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.






    share|improve this answer




















    • 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














    11












    11








    11








    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.






    share|improve this answer
















    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.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Apr 3 at 11:43

























    answered Apr 3 at 8:06









    max66max66

    39.6k74575




    39.6k74575







    • 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













    • 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








    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














    4














    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 :)






    share|improve this answer

























    • 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)); 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
















    4














    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 :)






    share|improve this answer

























    • 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)); 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














    4












    4








    4







    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 :)






    share|improve this answer















    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 :)







    share|improve this answer














    share|improve this answer



    share|improve this answer








    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)); 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


















    • 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)); 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

















    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












    3














    #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.






    share|improve this answer



























      3














      #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.






      share|improve this answer

























        3












        3








        3







        #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.






        share|improve this answer













        #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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Apr 3 at 8:12









        Martin MorterolMartin Morterol

        31316




        31316



























            draft saved

            draft discarded
















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            Adding axes to figuresAdding axes labels to LaTeX figuresLaTeX equivalent of ConTeXt buffersRotate a node but not its content: the case of the ellipse decorationHow to define the default vertical distance between nodes?TikZ scaling graphic and adjust node position and keep font sizeNumerical conditional within tikz keys?adding axes to shapesAlign axes across subfiguresAdding figures with a certain orderLine up nested tikz enviroments or how to get rid of themAdding axes labels to LaTeX figures

            Tähtien Talli Jäsenet | Lähteet | NavigointivalikkoSuomen Hippos – Tähtien Talli

            Do these cracks on my tires look bad? The Next CEO of Stack OverflowDry rot tire should I replace?Having to replace tiresFishtailed so easily? Bad tires? ABS?Filling the tires with something other than air, to avoid puncture hassles?Used Michelin tires safe to install?Do these tyre cracks necessitate replacement?Rumbling noise: tires or mechanicalIs it possible to fix noisy feathered tires?Are bad winter tires still better than summer tires in winter?Torque converter failure - Related to replacing only 2 tires?Why use snow tires on all 4 wheels on 2-wheel-drive cars?