基于 is_pointer 特性的模板特化

时间:2021-04-06 20:16:00

标签: c++ c++11

我确定之前已经回答过这个问题,但我不确定我的问题的正确术语/措辞是什么。

以下面的示例类为例:

class Fooable {
public:
    int foo(int a);
};

我想编写一个模板类,它可以调用任何泛型类型的 foo() 方法,无论它是指针类型还是引用:

template <typename T>
class FooableCaller {
public:
    void useFooWithSomeContext(?) {
        //This method needs to use the foo() method of some Fooable to
        int a = _getA();
        int b; //Returned from foo()

        //Depends on if the Fooable passed as an argument is a pointer or reference type
        //b = fooable.foo(a);
        //b = fooable->foo(a);

        _doWork(b);
    }
private:
    int _getA();
    void _doWork(int a);
};

int main() {
    Fooable f1;
    std::shared_ptr<Fooable> f2 = std::make_shared<Fooable>();

    //If I want to call foo() of f1, I have to do f1.foo();
    //If I want to call foo() of f2, I have to do f2->foo();
    //What is the correct want to write FooableCaller so that useFooWithSomeContext is select to use either . or -> depending on if T is reference or a pointer?

    FooableCaller<?> fc1;
    FooableCaller<?> fc2;

    fc1.useFooWithSomeContext(f1);
    fc2.useFooWithSomeContext(f2);
}

这是使用 std::is_pointer 特性的好地方吗?如果是,我该如何正确使用它?

我希望这是有道理的。

1 个答案:

答案 0 :(得分:0)

<块引用>

这是使用 std::is_pointer 特性的好地方吗?

不完全是,尽管特征会有所帮助。 std::is_pointer 确定类型是否为 cv 限定的原始指针,而您的示例使用类型 std::shared_ptr,一种类似指针的容器类型。您可以首先定义自己的特征来检测类型上的适当 operator*

template <typename Ptr, typename T>
using is_pointer_like_of = std::is_same<decltype(*std::declval<Ptr>()), T&>;

然后您可以将此特征与 std::enable_if 一起使用来定义以下对 SFINAE 友好的模板方法:

template <typename T>
class FooableCaller {
public:
    void callFoo(T& fooable) {
        // do a little more work
        fooable.foo();
    }

    template <typename Ptr>
    typename std::enable_if<is_pointer_like_of<Ptr, T>::value>::type callFoo(Ptr p) {
        callFoo(*p);
    }
};

必须使用 typename 说明符来表明 dependent name ::typestd::enable_if<...> 的成员 typedef,即 void,而不是成员值。

最后,您可以像这样使用 FooableCaller

int main() {
    Fooable f1;
    std::shared_ptr<Fooable> f2 = std::make_shared<Fooable>();
    FooableCaller<Fooable> fooableCaller;

    fooableCaller.callFoo(f1);
    fooableCaller.callFoo(f2);
}
相关问题