前回の質問からの続きです。私が持っているのは、次のような sfinae 依存チェーンを形成する一連の関数です (「A -> B」表記は、A の存在が B の存在に依存することを意味します):
S::f_base -> S::f -> ns::f_ -> f -> T::f
ここで、T はテンプレート引数です。次のように実装されています。
#include <utility>
struct S;
template <typename T>
auto f(S& s, T const& t) -> decltype(t.f(s), void())
{
t.f(s);
}
namespace ns
{
template <typename T>
auto f_(S& s, T const& t) -> decltype(f(s, t), void())
{
f(s, t);
}
}
struct S
{
template <typename T>
auto f(T const& t) -> decltype(ns::f_(std::declval<S&>(), t), void())
{
ns::f_(*this, t);
}
template <typename T>
auto f_base(T const* t_ptr) -> decltype(f(*t_ptr), void())
{
f(*t_ptr);
}
};
struct pass
{
void f(S&) const
{
}
};
struct fail
{
};
int main()
{
S s;
s.f(pass()); // compiles
//s.f(fail()); // doesn't compile
return 0;
}
意図したとおりに動作します。次のようS::f
に、クラス本体の定義とそのS::f_base
外側に定義を移動しようとすると、問題が発生します。
#include <utility>
struct S;
template <typename T>
auto f(S& s, T const& t) -> decltype(t.f(s), void())
{
t.f(s);
}
namespace ns
{
template <typename T>
auto f_(S& s, T const& t) -> decltype(f(s, t), void())
{
f(s, t);
}
}
struct S
{
template <typename T>
auto f(T const& t) -> decltype(ns::f_(std::declval<S&>(), t), void());
template <typename T>
auto f_base(T const* t_ptr) -> decltype(f(*t_ptr), void());
};
template <typename T>
auto S::f(T const& t) -> decltype(ns::f_(std::declval<S&>(), t), void())
{
ns::f_(*this, t);
}
template <typename T>
auto S::f_base(T const* t_ptr) -> decltype(f(*t_ptr), void()) // <---- HERE ---
{
f(*t_ptr);
}
int main()
{
return 0;
}
矢印でマークされた行では、GCC 4.7.1
不満を表しています。
エラー: 'decltype ((((S*)0)->S::f((* t_ptr)), void())) S::f_base(const T*)' のプロトタイプは、クラス内のいずれとも一致しません ' S'
エラー: 候補は: template decltype ((((S*)this)->S::f((* t_ptr)), void())) S::f_base(const T*)
(宣言と定義の両方で) を先頭に追加してf
、使用しているものを明示的に指定しようとしましたが、エラーは解決しません。f_base
std::declval<S&>().
次のように依存関係グラフを変更できることはわかっています。
S::f_base ->
-> ns::f_ -> f -> T::f
S::f ->
と一緒にS::f_base
依存するようにしますが、最初の依存グラフでこれを行う方法はありますか?ns::f_
S::f