【问题标题】:Is there anyway in C++11 to get member pointer type within a template?在 C++11 中是否有在模板中获取成员指针类型?
【发布时间】:2012-05-25 10:27:17
【问题描述】:

我知道这在 C++03 中是不可能的,但我希望有一些新的巫术可以让我做到这一点。见下文:

template <class T>
struct Binder
{
    template<typename FT, FT T::*PtrTomember>
    void AddMatch();
};
struct TestType
{
    int i;
};
int main(int argc, char** argv)
{
    Binder<TestType> b;
    b.AddMatch<int,&TestType::i>(); //I have to do this now
    b.AddMatch<&TestType::i>(); //I'd like to be able to do this (i.e. infer field type)
}

在 C++11 中有没有办法做到这一点? decltype 会有帮助吗?

** 更新:使用 Vlad 的示例,我在想这样的事情会起作用(警告:我没有编译,因为我现在正在构建具有 decltype 支持的编译器)

template <class T>
struct Binder
{
    template<typename MP, FT ft = decltype(MP)>
    void AddMatch()
    {
        //static_assert to make sure MP is a member pointer of T
    }
};
struct TestType
{
    int i;
};
int main()
{
    Binder<TestType> b;
    b.AddMatch<&TestType::i>();  
}

这行得通吗?

【问题讨论】:

  • 鉴于您明确指定它,我怀疑是否有办法。如果它是 AddMatch(&amp;TestType::i),它甚至应该在 C++03 中工作。
  • 您需要对指向成员的指针做什么?可能有比使用指向成员的指针作为非类型模板参数更好的解决方案。

标签: c++ templates c++11 decltype member-pointers


【解决方案1】:

你试图做的事情是做不到的,也就是说,除非你有类型,否则你不能将成员指针用作常量表达式。也就是说,必须提供非类型模板参数的类型,或者换句话说,模板参数没有类型推断。

【讨论】:

  • 其实我认为弗拉德是在正确的轨道上。我会稍微玩一下他的概念,看看它是否适合我正在做的事情......
  • @Jaime:你确定吗?在 Vlad 的代码中,模板的参数只是成员函数的 type,但成员函数并没有作为模板参数传递。如果要将指向成员的指针作为编译时常量,则需要将其称为:b.AddMatch&lt;decltype(&amp;TestType::i), &amp;TestType::i&gt;();,除非将其隐藏在宏后面(我不太喜欢一个主意)。如果您不介意将指向成员的指针作为运行时值,那么您可以将它传递给函数,编译器会推断它,但这会改变问题。
  • ...这是 kballo 在对您的问题的评论中指出的内容。
【解决方案2】:

这个怎么样(作为一个踢球者,它在 c++03 中工作):

#include <iostream>
#include <typeinfo>

template< typename T > struct ExtractMemberTypeHelper;
template< typename R, typename T >
struct ExtractMemberTypeHelper< R(T::*) >
{
    typedef R Type;
    typedef T ParentType;
};

template< typename T >
struct ExtractMemberType : public ExtractMemberTypeHelper< T > {};

struct foo
{
    int bar;
    template< typename T >
    void func( const T& a_Arg )
    {
        std::cout << typeid( typename ExtractMemberType< T >::Type ).name( ) << " " << typeid( typename ExtractMemberType< T >::ParentType ).name( ) << std::endl;
    }
};

int main()
{
    foo inst;
    inst.func( &foo::bar );
}

【讨论】:

  • 这就是两个 cmets 的建议:将模板参数更改为函数参数。如果您不需要/不希望指向成员的指针成为模板参数,那很好......
  • 啊,没错。但是,与仅将其作为类型推导的参数传递相比,我并没有看到发布者想要使用的接口有什么好处。
  • 好吧,在模板参数的情况下,生成的代码可能会稍微快一些,因为编译器可以注入确切的调用而不是通过指针调度,但正如你所说,在大多数情况下它会没有什么不同。 +1
【解决方案3】:

您可以让“T”提供此信息。

template <class ...T>
struct BoundTypes { };

template <class U, class T>
struct BinderDecls { 
  void AddMatch();
};

template <class U, class T, class ...Ts>
struct BinderDecls<U, BoundTypes<T, Ts...>>
  :BinderDecls<U, BoundTypes<Ts...>>
{ 
  using BinderDecls<U, BoundTypes<Ts...>>::AddMatch;

  template<T U::*PtrTomember>
  void AddMatch();
};

template <class T>
struct Binder : BinderDecls<T, typename T::bound_types> 
{ }

然后就简单了

struct TestType {
    typedef BoundTypes<int, float> bound_types;

    int i;
    float j;
};

int main(int argc, char** argv)
{
    Binder<TestType> b;
    b.AddMatch<&TestType::i>();
    b.AddMatch<&TestType::j>();
}

您也可以使用友元函数定义

template <class ...T>
struct BoundTypes { };

template <class U, class T>
struct BinderDecls {
  template<T U::*ptr>
  friend void addMatch(BinderDecl &u) {
   // ...
  }
};

template <class U, class ...Ts>
struct BinderDecls<U, BoundTypes<Ts...>> : BinderDecls<U, Ts>...
{ };

template<typename = void> 
void addMatch() = delete;

template <class T>
struct Binder : BinderDecls<T, typename T::bound_types> 
{ }

那你就可以写了

struct TestType {
    typedef BoundTypes<int, float> bound_types;

    int i;
    float j;
};

int main(int argc, char** argv)
{
    Binder<TestType> b;
    addMatch<&TestType::i>(b);
    addMatch<&TestType::j>(b);
}

【讨论】:

    【解决方案4】:
    template <class T>
    struct Binder
    {
        template<typename FT>
        void AddMatch();
    };
    
    struct TestType
    {
        int i;
    };
    
    int main()
    {
        Binder<TestType> b;
        b.AddMatch<decltype(&TestType::i)>();
    }
    

    【讨论】:

    • 是的,我敢打赌这会起作用,但我想阻止我的用户必须指定 decltype。我想我可以强制 FT 成为具有特征的成员字段并创建一个常量参数来获取 decltype(&TestType:i)...
    • 这不起作用。问题中的模板参数是非类型模板参数。函数 AddMatch 是在指向成员的指针上参数化的,而不是在指向成员的指针的类型上。
    • 这并没有解决最初的问题,它只是用更麻烦的decltype(&amp;TestType::i) 替换了第一个参数int(并且忘记提供指向成员的实际指针作为第二个模板参数...... ) 在原始代码中TestType::i 是一个已知值,在这个答案中实际值消失了(只有类型存在)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多