我有一个带有类化朋友函数声明的模板化类,当用更直接但看似等效的表达式表示时,其签名没有匹配:
link to example on online compiler
#include <type_traits>
template <typename Sig> class Base;
template <typename R, typename ... Args> class Base<R(Args...)> { };
template <typename Sig, typename T> class Derived;
template <typename Sig> struct remove_membership;
template <typename T, typename R, typename ... Args>
class Derived<R(Args...), T> : public Base<R(Args...)> {
static void bar() { }
// XXX: why are these two not equivalent, and only the 1st version successful?
template <typename T2>
friend auto foo(T2 const &) -> Base<typename
remove_membership<decltype(&std::remove_reference_t<T2>::operator())>::type> *;
template <typename T2>
friend auto foo(T2 const &) -> Base<R(Args...)> *;
};
template <typename F, typename R, typename ... Args>
struct remove_membership<R (F::*)(Args...) const> {
using type = R(Args...);
};
template <typename T>
auto foo(T const &) -> Base<typename
remove_membership<decltype(&std::remove_reference_t<T>::operator())>::type> *
{
using base_param_t = typename remove_membership<
decltype(&std::remove_reference_t<T>::operator())>::type;
Derived<base_param_t, T>::bar();
return nullptr;
}
int main(int, char **) { foo([](){}); } // XXX blows up if verbose friend decl. removed.
Derived<R(Args...), T>
的内部成员定义(例如,在bar()
的主体中),类型匹配,这使我感到困惑:
static_assert(std::is_same<Base<R(Args...)>, Base<typename
remove_membership<decltype(&std::remove_reference_t<T>::operator())>::type>>::value,
"signature mismatch");
围绕模板类的模板成员函数(和好友函数)的声明和实例化是否存在规则,这些规则使这些先前的声明在某些或所有情况下都与众不同?
答案 0 :(得分:2)
template <typename T2>
void foo(T2 const &)
template <typename T2>
auto foo(T2 const &)
-> std::enable_if_t<some_traits<T2>::value>;
有2种不同的重载。即使两个都返回void
(有效时)。
第二次过载使用SFINAE。
(是的,模板函数只能在返回类型上不同于常规函数)。
您的版本不完全相同,但相似(&std::remove_reference_t<T>::operator()
应该有效)
您可以使用更简单的模板好友功能:
template <typename T, typename R, typename ... Args>
class Derived<R(Args...), T> : public Base<R(Args...)> {
static void bar() { }
template <typename T2>
friend auto foo(T2 const &) -> Base<R(Args...)>*;
};
template <typename T>
auto foo(T const &) -> Base<void()>* // friend with Derived<void(), U>
{
using base_param_t = typename remove_membership<
decltype(&std::remove_reference_t<T>::operator())>::type;
Derived<base_param_t, T>::bar();
return nullptr;
}
但是您必须实现模板foo
的不同版本。
答案 1 :(得分:1)
问题可以减少为:
NumberOfMessagesSent
即使我们知道NumberOfMessagesReceived
始终是template<class T>
struct identity {
using type=T;
};
class X {
int bar();
public:
template<class T>
friend T foo();
};
template<class T>
typename identity<T>::type foo() { return X{}.bar(); }
int main() {
foo<int>(); // error: bar is a private member of X
}
,但编译器并不知道这一点,因此假设这样做是错误的。代码后面的某个地方可能会identity<T>::type
的一种特殊化,它会解析为T
以外的某种类型。
因此,当编译器看到identity<T>
的第二个声明时,将不会假定它与之前声明的同一个朋友T
。