次のコードのほとんどは、Piotr Skotnickiによってanswerから取得されています。ラムダオブジェクトはによって生成されたので、型パラメータ名を変更すると、テンプレートの置換が失敗する - コンパイラのバグ?
#include <iostream>
template <typename T>
struct identity { using type = T; };
template <typename...>
using void_t = void;
template <typename F>
struct call_operator;
template <typename C, typename R, typename... A>
struct call_operator<R(C::*)(A...)> : identity<R(A...)> {};
template <typename C, typename R, typename... A>
struct call_operator<R(C::*)(A...) const> : identity<R(A...)> {};
template <typename F>
using call_operator_t = typename call_operator<F>::type;
template <typename, typename = void_t<>>
struct is_convertible_to_function
: std::false_type {};
template <typename L>
struct is_convertible_to_function<L, void_t<decltype(&L::operator())>>
: std::is_assignable<call_operator_t<decltype(&L::operator())>*&, L> {};
template <typename, typename = void_t<>>
struct is_callable_object
: std::false_type {};
template <typename L>
struct is_callable_object<L, void_t<decltype(&L::operator())>>
: std::true_type {};
int main()
{
auto x = []() {};
std::cout << std::boolalpha << is_callable_object<decltype(x)>::value;
std::getchar();
}
これは予想通りtrue
を、印刷します。私はそれを試して、私は3
は、次のコードを考えてみましょうMSVC 14.0アップデートのバグであると信じるものを発見されましたコンパイラはoperator()
を実装しています。
のは、今(私が見たものから、is_convertible_to_function
原因この問題で使用されるタイプ名とは異なるもの)T
にL
からis_callable_object
に型パラメータ名を変更してみましょう。
template <typename, typename = void_t<>>
struct is_callable_object
: std::false_type {};
template <typename T>
struct is_callable_object<T, void_t<decltype(&T::operator())>>
: std::true_type {};
突然、これはfalse
を印刷します。 is_callable_object
はそれに依存しないので、is_convertible_to_funtion
は問題にならないはずです。実際、もし私がis_convertible_to_function
を取り除くと、この問題は消えてしまいます。私が望む任意のタイプ名を使うことができます。
私が言ったように、私はバグだと思うので、これはC++標準では奇妙な動作ではないことを確認するためにこの質問をしています。これに対する回避策は非常に簡単です。
あなたの声明があまりにも極端ではないかと疑問に思っていましたが、マイクロソフト自身でさえそれが認められます:https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for- expression-sfinae-in-vs-2015-update-1 /。ああ、私は実験を続けていきます、ありがとう。 – szczurcio