我确定之前已经回答过这个问题,但我不确定我的问题的正确术语/措辞是什么。
以下面的示例类为例:
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 特性的好地方吗?如果是,我该如何正确使用它?
我希望这是有道理的。
答案 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 ::type
是 std::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);
}