1

I want to use lambda as template parameter, but it will not compile in c++17. For example the temp_bar<int, lambda1> here does not work. It seems the non-type parameter is limited. Can anyone explain why this is not allowed? It will make life much easier to enable this.

template<typename T>
bool to_bool(T o)
{
    return bool(o);
}
template <typename T, auto F=to_bool<T>>
class temp_bar
{
public:
    temp_bar(T o)
            : _data{o}
    {
        if(F(o))
            std::cout << "OK\n";
    }
private:
    T _data;
};

int main()
{
    temp_bar<int> bar1{1};
    auto lambda1 = [](int o){return o==2;};
    temp_bar<int, lambda1> bar2{2};

    return 0;
}

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Wang
  • 7,250
  • 4
  • 35
  • 66
  • 1
    Template parameters must be known at compile time. A lambda is not created until runtime. – Remy Lebeau Feb 01 '20 at 03:48
  • 1
    You can in C++20: https://godbolt.org/z/3jkghn – parktomatomi Feb 01 '20 at 03:56
  • @RemyLebeau This is only true if you use capture. Without capture it is already knowable to compiler. – Wang Feb 01 '20 at 04:09
  • 1
    @Wang: "*Without capture it is already knowable to compiler.*" Nonsense. Lambdas are *objects*, regardless of whether they capture something. The `lambda1` object you created is not a `constexpr` object, so there was never any hope for putting it in a template parameter. – Nicol Bolas Feb 01 '20 at 04:41
  • 2
    A lambda is an object of **class** type. Those are categorically disallowed as template arguments until C++20. If that’s all you’re asking, this is a duplicate of the question you linked. – Davis Herring Feb 01 '20 at 04:51
  • What would be a practical use for such a lambda as NTTP? – fen May 11 '23 at 07:48

2 Answers2

0

This won't be possible without C++20. If you want to achieve a similar result in C++17, you can do the following

template<typename T>
bool to_bool(T o)
{
    return bool(o);
}
template <typename T >
class temp_bar
{
public:
    template <typename F >
    temp_bar(T o, F&& fn)
    : _data{o}
    {

        if(fn(o))
            std::cout << "OK\n";
    }

    temp_bar(T o) : _data(o) {
        if (to_bool(o))
            std::cout << "OK\n";
    }




private:
    T _data;


};

int main()
{
    temp_bar<int> bar1{1};
    auto lambda1 = [](int o){return o==2;};
    temp_bar<int> bar2{2,lambda1};

    return 0;
}

This effectively has two constructors, one without lambda and one with a lambda.

rwb
  • 621
  • 1
  • 12
  • 21
0

Ignoring the fact that the declaration of lambda1 is not constexpr and therefore is not a constant expression and therefore could never be used as a non-type template parameter (NTTP) regardless of anything else, the main reason this is not permitted is that lambdas are not a special thing in C++. A lambda is just a user-defined type created by the compiler with a specialized constructor, members based on your capture list, and an operator() overload in accord with the lambda function body and signature. There is nothing a lambda is doing that you couldn't do without them.

In C++, lambdas are just shorthand notation; nothing more.

As such, if user-defined types cannot be used as NTTPs, and lambdas are user-defined types, then you cannot use lambdas as NTTPs. That's why they're disallowed.

And note that, while C++20 does allow some user-defined types to be used as NTTPs, the standard at present offers no guarantees as to whether any particular lambda could be used as an NTTP. A user-defined type that is used as an NTTP must provide strong structural equality, and nothing in the standard requires that any lambda, even capture-less ones, provide strong structural equality. An implementation may do so, but such code is non-portable.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982