gpt4 book ai didi

C++ - 是否可以从模板中的成员函数类型中提取类和参数类型?

转载 作者:可可西里 更新时间:2023-11-01 18:28:29 25 4
gpt4 key购买 nike

我想用模板类包装符合“void (ClassType::Function)(ArgType)”类型的成员函数。稍后,我想将 ClassType 的实例传递给此模板的实例并让它调用包装方法:

class Foo {
public:
Foo() : f_(0.0) {}
void set(double v) { f_ = v * 2.1; }
double get() { return f_; }
private:
double f_;
};

template <typename ArgType, typename ClassType, void (ClassType::*Method)(ArgType)>
class Wrapper {
public:
explicit Wrapper(ClassType *cls) : cls_(cls) {}

void do_something(ArgType value) {
(cls_->*Method)(value);
}

private:
ClassType *cls_;
};

#include <iostream>
int main(int argc, char ** argv) {
Foo foo;
Wrapper<double, Foo, &Foo::set> wrapper(&foo);

wrapper.do_something(1.0);
std::cout << foo.get() << std::endl;
// outputs "2.1"
return 0;
}

注意在 Wrapper<> 的实例化中“Foo”被指定了两次 - 它在这里看起来是多余的。

所以我想知道是否可以避免使用模板参数ClassType。例如,如果可以从成员函数指针参数中暗示或提取它,那么就不需要在 Wrapper<> 的实例化中显式指定。

以类似的方式,避免显式指定 ArgType 也会很有用,因为(也许)它可以从 Foo::set 中确定?

这在 C++ 中可行吗?也许沿着这些(完全是幻想的)路线:

template <void (ClassType::*Method)(ArgType)>
class Wrapper2 {
public:
explicit Wrapper(Method::ClassType *cls) : cls_(cls) {}

void do_something(Method::ArgType value) {
(cls_->*Method)(value);
}

private:
Method::ClassType *cls_;
};

// ...

int main() {
Foo foo;
Wrapper<&Foo::set> wrapper(&foo);
// ...
}

或者,也许可以调用另一个级别的模板魔法来执行以下操作:

Wrapper<Magic<&Foo::set> > wrapper(&foo);

我很想知道哪些机制可用(如果有的话)。

我要求使用 C++03,而不是 C++11,但我也想知道 C++11 可能提供什么。

编辑:更多信息——我打算使用这种机制来包装约 300 个成员函数(全部属于 ClassType,或一组非常相似的类),但只需要考虑大约六个左右的签名:

  • void (ClassType::Function)(ArgType) - 其中 ArgType 为“ float ”
  • void (ClassType::Function)(ArgType) - 其中 ArgType 是“整数”
  • void (ClassType::Function)(bool)
  • void (ClassType::Function)(IndexType, ArgType) - 以上三个带有额外的“索引”参数

例如,成员函数是我在大型配置“集合”类中称为“属性”的“setter”函数(而不是上面的简单 Foo):

class MyPropertyCollection {
public:
void set_oink(double value) { oink_ = value; }
void set_bar(int value) { bar_ = value; }
void set_squee(bool value) { squee_ = value; }
private:
double oink_;
int bar_;
bool squee_;
};

// elsewhere
WrapperCollection wrapper_collection; // a simple set of wrapper objects, accessed by id
MyPropertyCollection property_collection;
wrapper_collection.add(PROPERTY_OINK_ID, new Wrapper<double, MyPropertySet, &MyPropertySet::set_oink>(&property_collection);
wrapper_collection.add(PROPERTY_BAR_ID, new Wrapper<int, MyPropertySet, &MyPropertySet::set_bar>(&property_collection);
wrapper_collection.add(PROPERTY_SQUEE_ID, new Wrapper<bool, MyPropertySet, &MyPropertySet::set_squee>(&property_collection);
// +300 more

最佳答案

struct MyClass
{
MyClass& Move(MyClass& m) { return *this; }
};

typedef MyClass& (MyClass::*MethodT) (MyClass&);

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

template< typename R, typename C, typename A >
struct ExtractType< R (C::*)(A) >
{
typedef C type;
};

static_assert( std::is_same< ExtractType< MethodT >::type, MyClass >::value, "oops" );

它似乎适用于我的 gcc 4.8 版本。
它的工作方式就像我在评论中提到的那样,它是编译器在特化检查期间执行的“反向模式匹配”。这是非常强大的。
所以你看,我们指定了某种模式,如果类型 T 遵守,它将被编译器分解为组成它的三个子类型:RCA。即返回类型、类类型和参数。

但是您可以看到它适用于一个参数。当我们有未定义数量的参数时怎么办?
也许是一个检查器类列表,或者使用可变参数模板?

老实说,我什至不确定这是否适用于 void。我认为 void 总是不可能放在模板中,因此它会导致这个 ExtractType 类的许多版本支持所有可能声明的组合。或者在我看来是这样。

编辑:

好吧,我完全随机地放弃了它,但它似乎在 C++11 中比我预期的要好得多,这在 gcc 4.8 上没问题:

struct MyClass
{
};

typedef int (MyClass::*MethodT) (bool);
typedef void (MyClass::*VV) ();
typedef void (MyClass::*IL) (int, long);

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

template< typename R, typename C, class...A >
struct ExtractType< R (C::*)(A...) >
{
typedef C type;
typedef R returntype;
};

static_assert( std::is_same< ExtractType< MethodT >::type, MyClass >::value, "oops" );
static_assert( std::is_same< ExtractType< VV >::type, MyClass >::value, "oops" );
static_assert( std::is_same< ExtractType< IL >::type, MyClass >::value, "oops" );

static_assert( std::is_same< ExtractType< MethodT >::returntype, int >::value, "oops" );
static_assert( std::is_same< ExtractType< VV >::returntype, void >::value, "oops" );
static_assert( std::is_same< ExtractType< IL >::returntype, void >::value, "oops" );

疯狂的部分是它不介意返回类型中的 void。当然是 C++11。

关于C++ - 是否可以从模板中的成员函数类型中提取类和参数类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14783876/

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