C++ 在使用CRTP的类中检测成员函数
我试图根据使用CRTP的子类中可用的函数来定制基类的实现 我想要什么的基本想法:C++ 在使用CRTP的类中检测成员函数,c++,c++14,sfinae,crtp,C++,C++14,Sfinae,Crtp,我试图根据使用CRTP的子类中可用的函数来定制基类的实现 我想要什么的基本想法: // has_inc_function<Child, void> should detect the presence of a member function void Child::inc() template<class Child, bool = has_inc_function<Child, void>::value> struct base { // ...
// has_inc_function<Child, void> should detect the presence of a member function void Child::inc()
template<class Child, bool = has_inc_function<Child, void>::value>
struct base
{
// ... base implementation stuff
};
template<class Child>
struct base<Child, true>
{
// ... base specialization implementation stuff
};
struct empty : public base<empty>
{};
struct has_inc
{
void inc()
{}
};
struct has_inc_and_crtp : public base<has_inc_and_crtp>
{
void inc()
{}
};
struct has_inc_and_misuse_crtp : public base<has_inc_and_misuse_crtp, true>
{
void inc()
{}
};
struct has_inc_and_misuse_crtp2 : public base<has_inc_and_misuse_crtp, false>
{
void inc()
{}
};
struct no_inc_and_misuse_crtp : public base<no_inc_and_misuse_crtp, true>
{
};
int main()
{
static_assert(has_inc_function<empty, void>::value == false, "");
static_assert(has_inc_function<has_inc, void>::value == true, "");
static_assert(has_inc_function<has_inc_and_crtp, void>::value == true, "");
static_assert(has_inc_function<has_inc_and_misuse_crtp, void>::value == true, "");
static_assert(has_inc_function<has_inc_and_misuse_crtp2, void>::value == true, "");
static_assert(has_inc_function<no_inc_and_misuse_crtp, void>::value == false, "");
}
():
注意:这是因为实现与返回类型不匹配。为了在C++14中实现这一点,我还包括了Library fundamentals TS v2中的示例实现
struct nonesuch
{
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
namespace detail {
template <class Default, class AlwaysVoid,
template<class...> class Op, class... Args>
struct detector {
using value_t = std::false_type;
using type = Default;
};
template <class Default, template<class...> class Op, class... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
using value_t = std::true_type;
using type = Op<Args...>;
};
} // namespace detail
template <template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
template <template<class...> class Op, class... Args>
using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;
template <class Default, template<class...> class Op, class... Args>
using detected_or = detail::detector<Default, void, Op, Args...>;
template<class...> struct disjunction : std::false_type { };
template<class B1> struct disjunction<B1> : B1 { };
template<class B1, class... Bn>
struct disjunction<B1, Bn...>
: std::conditional_t<bool(B1::value), B1, disjunction<Bn...>> { };
template <typename T>
using has_type_t = typename T::inc;
template <typename T>
using has_non_type_t = decltype(&T::inc);
template <typename T, class RetType>
using has_inc_function =
disjunction<is_detected<has_type_t, T>, is_detected<has_non_type_t, T>>;
struct非这样
{
~nonesoch()=删除;
非等(非等常数&)=删除;
void运算符=(非等常数&)=删除;
};
名称空间详细信息{
模板
结构检测器{
使用value\u t=std::false\u类型;
使用类型=默认值;
};
模板
struct detector您想要的是这种形式,这显然是不可能的。在类完成之前,必须知道类的父类,因此在知道类是否有这样的成员函数之前
你能做的有点取决于base的不同实例化的不同程度。如果它们基本上是相同的接口,具有不同的实现细节,你可以编写另一个具有相同接口和变量成员的类(std::variant
是C++17,但你可以用动态多态性做同样的事情)然后在实例化时可以决定使用哪个
您也可以尝试以下方向:
#包括
#包括
模板
结构基{
int foo();
};
struct has_inc:base{
void公司();
};
结构具有\u非\u inc:base{
};
模板
结构模拟{
int foo(base*){return 1;}
};
模板
结构模拟{
int foo(base*){return 0;}
};
模板
int base::foo(){
返回mock().foo(this);
}
int main(){
has_inc h;
没有公司;
标准::cout
我已经尝试了各种不同的实现has_inc_函数
,但是在has_inc_和_crtp
的情况下,它们似乎都失败了,我不知道为什么
问题(如果我理解正确)是,在has_inc_和_crpt
情况下,首先计算has_inc_函数的值
,以确定子项的第二个模板参数的默认值
template<class Child, bool = has_inc_function<Child, void>::value>
struct base
// ........................................................V different from the default
template<class Child, bool = has_inc_function<Child, void, 1>::value>
struct base
保持false
我将如何实现has_inc_函数
,使其在所有这些测试用例中都能像我所期望的那样工作,或者我想要的是不可能的
一个快速而肮脏的解决方案可能是向has_inc_函数
添加一个额外的虚拟默认模板参数
以身作则
// ................................VVVVVVV dummy and defaulted
template <typename C, typename RT, int = 0>
struct has_inc_function
因此,当您在静态断言中使用has_inc_functin
时
static_assert(has_inc_function<has_inc_and_crtp, void>::value == true, "");
听起来你想要“反射”。这是C++没有的特性。J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J
static_assert(has_inc_function<has_inc_and_crtp, void>::value == true, "");
// ................................VVVVVVV dummy and defaulted
template <typename C, typename RT, int = 0>
struct has_inc_function
// ........................................................V different from the default
template<class Child, bool = has_inc_function<Child, void, 1>::value>
struct base
static_assert(has_inc_function<has_inc_and_crtp, void>::value == true, "");
#include <type_traits>
template <typename C, typename RT, int = 0>
struct has_inc_function
{
private:
template <typename T>
static constexpr auto check(T *) ->
typename std::is_same<decltype(std::declval<T>().inc()), RT>::type;
template <typename>
static constexpr std::false_type check(...);
using type = decltype(check<C>(nullptr));
public:
/// @brief True if there is an inc member function
static constexpr bool value = type::value;
};
template <typename Child, bool = has_inc_function<Child, void, 1>::value>
struct base
{ };
template <typename Child>
struct base<Child, true>
{ };
struct empty : public base<empty>
{ };
struct has_inc
{ void inc() {} };
struct has_inc_and_crtp : public base<has_inc_and_crtp>
{ void inc() {} };
struct has_inc_and_misuse_crtp : public base<has_inc_and_misuse_crtp, true>
{ void inc() {} };
struct has_inc_and_misuse_crtp2 : public base<has_inc_and_misuse_crtp, false>
{ void inc() {} };
struct no_inc_and_misuse_crtp : public base<no_inc_and_misuse_crtp, true>
{ };
template <typename C, typename RT>
constexpr auto hif_v = has_inc_function<C, RT>::value;
int main ()
{
static_assert(hif_v<empty, void> == false, "");
static_assert(hif_v<has_inc, void> == true, "");
static_assert(hif_v<has_inc_and_crtp, void> == true, "");
static_assert(hif_v<has_inc_and_misuse_crtp, void> == true, "");
static_assert(hif_v<has_inc_and_misuse_crtp2, void> == true, "");
static_assert(hif_v<no_inc_and_misuse_crtp, void> == false, "");
}