我正在使用 C++17。我有如下代码:

#include <type_traits>

template <typename T>
struct Fooer
{
    Fooer (T & fooable)
    {
        fooable . foo ();
    }
};

template <typename T>
Fooer (T & fooable) -> Fooer <T>;

struct Fooable
{
private:

    void
    foo ();

    friend struct Fooer <Fooable>;
};

struct NotFooable
{
};

我想实现一个可以判断类型是否为“Fooable”的类型特征。

我无法检查该类型是否有 foo () 方法,因为它是私有(private)方法。这也不会告诉我 Fooer 的构造函数是否可以调用该方法。
// Checking for the foo method doesn't work.

template <typename T, typename = void>
struct HasFoo;

template <typename T, typename>
struct HasFoo : std::false_type
{
};

template <typename T>
struct HasFoo
<
    T,
    std::enable_if_t
    <
        std::is_convertible_v <decltype (std::declval <T> () . foo ()), void>
    >
>
:   std::true_type
{
};

// Both of these assertions fail.
static_assert (HasFoo <Fooable>::value);
static_assert (HasFoo <NotFooable>::value);

我也无法检查 Fooer <T> 是否可通过 std::is_constructible 构造,因为 std::is_constructible 不检查构造函数定义是否格式正确,仅检查表达式 Fooer <T> fooer (std::declval <T> ())
// Checking constructibility doesn't work either.

template <typename T, typename = void>
struct CanMakeFooer;

template <typename T, typename>
struct CanMakeFooer : std::false_type
{
};

template <typename T>
struct CanMakeFooer
<
    T,
    std::enable_if_t <std::is_constructible_v <Fooer <T>, T &>>
>
:   std::true_type
{
};

// Neither of these assertions fail.
static_assert (CanMakeFooer <Fooable>::value);
static_assert (CanMakeFooer <NotFooable>::value);

如果我真的尝试调用构造函数,我会得到我期望的错误,尽管它并没有让我更接近实现类型特征。
void
createFooer ()
{
    Fooable fooable;
    NotFooable not_fooable;

    // This works fine.
    { Fooer fooer (fooable); }

    // This correctly generates the compiler error: no member named 'foo' in
    // 'NotFooable'
    { Fooer fooer (not_fooable); }
}

我想避免将类型特征声明为 Fooable 类型的 friend ,并且我想避免公开 'foo'。

如果我能以某种方式让类型特征检查函数或构造函数的定义是否正确,我可以很容易地实现这个类型特征,但我不知道如何做到这一点,我找不到任何例子互联网上有这样的事情。

可以做我想做的吗?我该怎么做呢?

最佳答案

这里的问题是 Fooer 的构造函数不是“SFINAE-friendly”的。它要求 Fooer 可以调用 fooable.foo() ,但就 C++ 而言,声明 Fooer(T &); 没有任何此类约束。

我们可以将构造函数声明更改为构造函数模板,以便当类模板的模板参数不是“fooable”时模板参数推导失败:

#include <utility>

template <typename T>
struct Fooer
{
    template <typename U = T, typename Enable =
                std::void_t<decltype(std::declval<U&>().foo())>>
    Fooer (T & fooable)
    {
        fooable . foo ();
    }
};

[使用 C++20 约束,这将变得更容易和更清晰:
// C++20 code
template <typename T>
struct Fooer
{
     Fooer (T & fooable) requires requires { fooable.foo(); }
     {
         fooable . foo ();
     }
};

]

有了这个改变,你的 CanMakeFooer 应该可以工作了。虽然它可以更简单地定义为仅使用主模板而没有特化:
template <typename T>
struct CanMakeFooer :
    public std::bool_constant<std::is_constructible_v<Fooer<T>, T&>>
{};

Demo on coliru.

关于c++ - 如何构造一个类型特征来判断一种类型的私有(private)方法是否可以在另一种类型的构造函数中调用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59204036/

10-11 23:01
查看更多