[英]C++ detection idiom failure with inheritance
The below code fails to compile. 以下代码无法编译。 For some reason inheriting from
HasFoo
causes IsWrapper
to fail. 由于某种原因,从
HasFoo
继承会导致IsWrapper
失败。 It has something to do with the friend
function foo()
because inheriting from other classes seems to work fine. 它与
friend
函数foo()
因为从其他类继承似乎可以正常工作。 I don't understand why inheriting from HasFoo
causes the detection idiom to fail. 我不明白为什么从
HasFoo
继承会导致检测惯用法失败。
What is the proper way to detect WithFoo
as a Wrapper
? 将
WithFoo
检测为Wrapper
程序的正确方法是什么?
https://godbolt.org/z/VPyarN https://godbolt.org/z/VPyarN
#include <type_traits>
#include <iostream>
template<typename TagType, typename ValueType>
struct Wrapper {
ValueType V;
};
// Define some useful metafunctions.
template<typename Tag, typename T>
T BaseTypeImpl(const Wrapper<Tag, T> &);
template<typename T>
using BaseType = decltype(BaseTypeImpl(std::declval<T>()));
template<typename Tag, typename T>
Tag TagTypeImpl(const Wrapper<Tag, T> &);
template<typename T>
using TagType = decltype(TagTypeImpl(std::declval<T>()));
// Define VoidT. Not needed with C++17.
template<typename... Args>
using VoidT = void;
// Define IsDetected.
template<template <typename...> class Trait, class Enabler, typename... Args>
struct IsDetectedImpl
: std::false_type {};
template<template <typename...> class Trait, typename... Args>
struct IsDetectedImpl<Trait, VoidT<Trait<Args...>>, Args...>
: std::true_type {};
template<template<typename...> class Trait, typename... Args>
using IsDetected = typename IsDetectedImpl<Trait, void, Args...>::type;
// Define IsWrapper true if the type derives from Wrapper.
template<typename T>
using IsWrapperImpl =
std::is_base_of<Wrapper<TagType<T>, BaseType<T>>, T>;
template<typename T>
using IsWrapper = IsDetected<IsWrapperImpl, T>;
// A mixin.
template<typename T>
struct HasFoo {
template<typename V,
typename std::enable_if<IsWrapper<T>::value &&
IsWrapper<V>::value>::type * = nullptr>
friend void foo(const T &This, const V &Other) {
std::cout << typeid(This).name() << " and " << typeid(Other).name()
<< " are wrappers\n";
}
};
template<typename Tag>
struct WithFoo : public Wrapper<WithFoo<Tag>, int>,
public HasFoo<WithFoo<Tag>> {};
int main(void) {
struct Tag {};
WithFoo<Tag> WrapperFooV;
// Fails. Why?
static_assert(IsWrapper<decltype(WrapperFooV)>::value,
"Not a wrapper");
return 0;
}
I don't understand why inheriting from
HasFoo
causes the detection idiom to fail.我不明白为什么从
HasFoo
继承会导致检测惯用法失败。
Isn't completely clear to me also but surely a problem is that you use IsWrapper<T>
inside the body of HasFoo<T>
and, when you inherit HasFoo<WithFoo<Tag>>
from WithFoo<Tag>
you have that WithFoo<Tag>
is incomplete when you check it with IsWrapper
. 对我来说还不是很清楚,但是肯定是有一个问题是,您在
IsWrapper<T>
的主体内使用HasFoo<T>
并且当您从WithFoo<Tag>
继承HasFoo<WithFoo<Tag>>
,您有了WithFoo<Tag>
使用IsWrapper
检查时, WithFoo<Tag>
不完整。
A possible solution (I don't know if acceptable for you) is define (and SFINAE enable/disable) foo()
outside HasFoo
. 一个可能的解决方案(我不知道是否可以接受)是在
HasFoo
之外定义(和SFINAE启用/禁用) foo()
。
I mean... try rewriting HasFoo
as follows 我的意思是...尝试如下重写
HasFoo
template <typename T>
struct HasFoo {
template <typename V>
friend void foo(const T &This, const V &Other);
};
and defining foo()
outside 并在外面定义
foo()
template <typename T, typename V>
std::enable_if_t<IsWrapper<T>::value && IsWrapper<V>::value>
foo(const T &This, const V &Other) {
std::cout << typeid(This).name() << " and " << typeid(Other).name()
<< " are wrappers\n";
}
What is the proper way to detect WithFoo as a Wrapper?
将WithFoo检测为包装程序的正确方法是什么?
Sorry but your code is too complicated for me. 抱歉,您的代码对我来说太复杂了。
I propose the following (simpler, I hope) alternative 我提出以下(我希望更简单)的替代方案
#include <type_traits>
#include <iostream>
template<typename TagType, typename ValueType>
struct Wrapper {
ValueType V;
};
template <typename T1, typename T2>
constexpr std::true_type IW_helper1 (Wrapper<T1, T2> const &);
template <typename T>
constexpr auto IW_helper2 (T t, int) -> decltype( IW_helper1(t) );
template <typename T>
constexpr std::false_type IW_helper2 (T, long);
template <typename T>
using IsWrapper = decltype(IW_helper2(std::declval<T>(), 0));
template <typename T>
struct HasFoo {
template <typename V>
friend void foo(const T &This, const V &Other);
};
template <typename T, typename V>
std::enable_if_t<IsWrapper<T>::value && IsWrapper<V>::value>
foo(const T &This, const V &Other) {
std::cout << typeid(This).name() << " and " << typeid(Other).name()
<< " are wrappers\n";
}
template<typename Tag>
struct WithFoo : public Wrapper<WithFoo<Tag>, int>,
public HasFoo<WithFoo<Tag>> {};
int main () {
struct Tag {};
WithFoo<Tag> WrapperFooV;
static_assert(IsWrapper<decltype(WrapperFooV)>::value,
"Not a wrapper");
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.