gpt4 book ai didi

C++ 检测习语失败与继承

转载 作者:行者123 更新时间:2023-11-30 03:14:56 26 4
gpt4 key购买 nike

下面的代码编译失败。由于某些原因,从 HasFoo 继承会导致 IsWrapper 失败。它与 friend 函数 foo() 有关,因为从其他类继承似乎工作正常。我不明白为什么从 HasFoo 继承会导致检测惯用语失败。

WithFoo 检测为 Wrapper 的正确方法是什么?

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.

我也不完全清楚,但问题肯定是你使用 IsWrapper<T>HasFoo<T> 的体内而且,当你继承 HasFoo<WithFoo<Tag>>来自 WithFoo<Tag>你有那个WithFoo<Tag>IsWrapper 检查时不完整.

一个可能的解决方案(我不知道你是否可以接受)是定义(和 SFINAE 启用/禁用)foo()外面HasFoo .

我的意思是...尝试重写 HasFoo如下

template <typename T>
struct HasFoo {
template <typename V>
friend void foo(const T &This, const V &Other);
};

并定义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?

抱歉,您的代码对我来说太复杂了。

我提出以下(我希望更简单)替代方案

#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");
}

关于C++ 检测习语失败与继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57384751/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com