と同様に機能するメソッドを持つコンテナのようなクラスがありstd::apply
ます。このメソッドを修飾子でオーバーロードしたいのですが、const
このメソッドをジェネリック ラムダで呼び出そうとすると、 のインスタンス化からハード エラーが発生しますstd::invoke_result_t
。std::invoke_result_t
メソッドの戻り値を推測し、引数の SFINAE チェックを実行するために使用しています。
#include <type_traits>
#include <utility>
template <typename T>
class Container
{
public:
template <typename F>
std::invoke_result_t<F, T &> apply(F &&f)
{
T dummyValue;
return std::forward<F>(f)(dummyValue);
}
template <typename F>
std::invoke_result_t<F, const T &> apply(F &&f) const
{
const T dummyValue;
return std::forward<F>(f)(dummyValue);
}
};
int main()
{
Container<int> c;
c.apply([](auto &&value) {
++value;
});
return 0;
}
Clang 6.0 でコンパイル中のエラー メッセージ:
main.cc:27:9: error: cannot assign to variable 'value' with const-qualified type 'const int &&'
++value;
^ ~~~~~
type_traits:2428:7: note: in instantiation of function template specialization 'main()::(anonymous class)::operator()<const int &>' requested here
std::declval<_Fn>()(std::declval<_Args>()...)
^
type_traits:2439:24: note: while substituting deduced template arguments into function template '_S_test' [with _Fn = (lambda at main.cc:26:13), _Args = (no value)]
typedef decltype(_S_test<_Functor, _ArgTypes...>(0)) type;
^
type_traits:2445:14: note: in instantiation of template class 'std::__result_of_impl<false, false, (lambda at main.cc:26:13), const int &>' requested here
: public __result_of_impl<
^
type_traits:2831:14: note: in instantiation of template class 'std::__invoke_result<(lambda at main.cc:26:13), const int &>' requested here
: public __invoke_result<_Functor, _ArgTypes...>
^
type_traits:2836:5: note: in instantiation of template class 'std::invoke_result<(lambda at main.cc:26:13), const int &>' requested here
using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
^
main.cc:16:10: note: in instantiation of template type alias 'invoke_result_t' requested here
std::invoke_result_t<F, const T &> apply(F &&f) const
^
main.cc:26:7: note: while substituting deduced template arguments into function template 'apply' [with F = (lambda at main.cc:26:13)]
c.apply([](auto &&value) {
^
main.cc:26:23: note: variable 'value' declared const here
c.apply([](auto &&value) {
~~~~~~~^~~~~
std::invoke_result_t
SFINAE に適しているかどうかはわかりませんが、末尾の戻り値の型に置き換えてみたので、ここでは問題ではないと思います。たとえば、次のようになります。
auto apply(F &&f) const -> decltype(std::declval<F>()(std::declval<const T &>()))
同様のエラーが発生しました:
main.cc:27:9: error: cannot assign to variable 'value' with const-qualified type 'const int &&'
++value;
^ ~~~~~
main.cc:16:41: note: in instantiation of function template specialization 'main()::(anonymous class)::operator()<const int &>' requested here
auto apply(F &&f) const -> decltype(std::declval<F>()(std::declval<const T &>()))
^
main.cc:26:7: note: while substituting deduced template arguments into function template 'apply' [with F = (lambda at main.cc:26:13)]
c.apply([](auto &&value) {
^
main.cc:26:23: note: variable 'value' declared const here
c.apply([](auto &&value) {
~~~~~~~^~~~~
質問:
- なぜこれが起こるのですか?より正確には、オーバーロードの解決中にラムダの本体がインスタンス化されるのはなぜですか?
- どうすれば回避できますか?