Given the following code
#include <type_traits>
#include <utility>
template <typename T>
class Something {
public:
template <typename F>
auto foo(F&&)
-> decltype(std::declval<F>()(std::declval<T&>())) {}
template <typename F>
auto foo(F&&) const
-> decltype(std::declval<F>()(std::declval<const T&>())) {}
};
int main() {
auto something = Something<int>{};
something.foo([](auto& val) {
++val;
});
}
https://wandbox.org/permlink/j24Pe9qOXV0oHcA8
When I try to compile this I get the error saying that I am not allowed to modify a const value in the lambda in main. This means that somehow the templates are both being instantiated in the class and this is causing a hard error since the error is in the body of the lambda.
What are the rules regarding this? Why does overload resolution try to instantiate a template that will never be called? The const one should never be called here so why does it try to fully instantiate it?
However strange thing here is that when I change the definitions to return by decltype(auto)
and add the code to do the same thing as the trailing return types suggest, I don't see an error. Indicating that the templates are not fully being instantiated?
template <typename F>
decltype(auto) foo(F&& f) {
auto t = T{};
f(t);
}
template <typename F>
decltype(auto) foo(F&& f) const {
const auto t = T{};
f(t);
}
I guess the compiler doesn't know which function to call before instantiating at least the signature with the passed function. But that doesn't explain why the decltype(auto) version works...