C++ SFINAE的方法组和装饰器。

问题描述 投票:0回答:1

我有一个std::variants,包含有不同接口的对象。目标是调用一些方法,如果变体中的对象有它的话.我正试图做几个模板装饰器,并寻找一种方法,以较少的模板和没有宏的方式来实现它。最后,我的想法看起来像。

class Good
{
public:
    void a(int);
    float b(float);
    int c(double);
};

class Bad
{
public:
    void a(int);
    int c(double);
};

template<class T>
class View : protected T
{
public:
    using T::a;
    using T::b;
};
template<class T, template<class> class V>
constexpr bool IsFitToView = // ??
//usage

std::variant<Good, Bad> variant = //;
std::visit([](auto&& obj) {
    if constexpr(IsFitToView<std::decay_t<decltype(obj)>, View>)
    {
       View view{obj}; // create view from obj
       //here work with obj as view, calling a `a` and `b` methods;
    }
}, variant);

主要问题是如何创建IsFitToView检查。我的方法是。

template<class T, template<class> class V, class = void>
struct IsFit : std::false_type
{};

template<class T, template<class> class V>
struct IsFit<T, V, std::void_t<V<T>>> : std::true_type
{};

template<class T, template<class> class V>
constexpr bool IsFitToView = IsFit<T, V>::value;

我希望它能像SFINAE那样工作。View<Good> 编译和选择模板专用化 View<Bad> 不能编纂,因为 using T::b; 在...中 View...但它对好类型和坏类型都返回了真值!我知道我可以通过检查方法的存在来检查它,像这样检查。

std::cout << IsFitToView<Good, View> << IsFitToView<Bad, View>;

我知道我可以通过逐个检查来检查方法的存在性,比如说

if constexpr(HasAFunc<T> && HasBFunc<T> && ...

但我必须创建许多不同的 Views. 它非常啰嗦,而且很难读懂.请你解释一下为什么我的方法行不通,并给出任何想法来做我想要的事情。谢谢!我有一个std::variants,其中包含有不同接口的对象。

c++ templates c++17 sfinae
1个回答
1
投票

你能解释一下为什么我的方法不能用吗?

你目前的方法与 using 声明失败,因为类的(View的)主体实例化发生在 即时语境,这意味着它不能导致软错误,从而导致回落至 IsFit 主模板,因此它的特殊化总是能产生更好的匹配,从而导致 IsFitToView 始终 true.

即使这工作。using T::a; 不会告诉你任何关于 a. 它可以是一个函数,一个重载的函数集,一个 static 或非static 数据成员,甚至是某个类型的别名,而这个类型恰好存在于 T的范围。


你能不能给点想法来做我想要的事情?

知道了如何检查函数的存在性,你可以将视图定义为变量模板,将一般谓词分组,例如:。

template <typename T>
inline constexpr bool ViewAB = HasAFunc<T> && HasBFunc<T>;

有了这个,你就可以检查了。

if constexpr (ViewAB<std::decay_t<decltype(obj)>>)

另一个解决方案是使用... 侦测成语 表库基础知识v2。

template <typename T>
using ViewAB = decltype(std::declval<T>().a(3), std::declval<T>().b(3.14f));

template <typename T>
using ViewC = decltype(std::declval<T>().c(2.7271));

并像这样使用它。

if constexpr (std::experimental::is_detected_v<ViewAB, decltype(obj)>)

DEMO


或者,在 ,你可以将视图定义为概念。

template <typename T>
concept ViewAB = requires (T t)
{
    t.a(1);
    t.b(3.14f);
};

它不仅使代码更容易阅读,清晰地展示了需求与示例用法,而且还产生了一个错误信息,解释哪个约束没有被满足。

DEMO 2

© www.soinside.com 2019 - 2024. All rights reserved.