首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++自动推导模板成员指针类型

C++自动推导模板成员指针类型
EN

Stack Overflow用户
提问于 2020-11-20 15:19:59
回答 3查看 425关注 0票数 4

我有这样的代码:

代码语言:javascript
复制
struct Test {
    std::string s;
};

template <typename T,
         auto T::* groupPtr>    
         struct Base{
             using BaseType = typename std::decay<decltype(std::declval<T>().*groupPtr)>::type;

             void Process(const Test * e){
                 printf("%s\n", e->s.c_str());

                 BaseType tmp = e->*groupPtr;       
                 printf("%s\n", tmp.c_str());
             }
         };

int main(){
    Test t;
    t.s = "x";

    Base<Test, &Test::s> r;
    r.Process(&t);
}

但是,编译以一个错误结束:

代码语言:javascript
复制
main.cpp: error C2440: 'specialization': cannot convert from
'std::string Test::* ' to 'auto Test::* '

main.cpp: message : Types pointed to are unrelated; conversion
requires reinterpret_cast, C-style cast or function-style cast

main.cpp: error C3535: cannot deduce type for 'auto Test::* ' from
'int'

main.cpp: message : see reference to class template instantiation
'Base<Test,0>' being compiled

在启用C++17的情况下,我使用Visual 2019。

为什么建筑不能自动推导?或者甚至有可能?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-11-20 20:44:41

c++似乎忘记了在TMP中包括成员指针的自动扣减。我试过c++20,但失败了。这是个大问题。但是,我们可以找到一个解决办法,如下所示。

  • 压缩您的代码应该可以工作,但并不是因为“c++限制”。我们只会修改一点。如下所示。结构测试{ std::string s;};模板 struct { void (const* e){ printf("%s\n",e->S.C_str();BaseType tmp = e->*groupPtr;printf("%s\n",tmp.c_str());} };int main(){ Test t;}(测试:*s)=&Test::s;std::decay::type,s> r;r.Process(&t);}

上面的编码终于起作用了。

票数 2
EN

Stack Overflow用户

发布于 2020-11-21 05:34:02

Clang是正确的,该代码是有效的:auto可以用作函数、变量或模板参数的任何类型声明的decl说明符。另一方面,你不能在声明中的其他地方使用它:

代码语言:javascript
复制
int auto::*f() {…}      // not in a ptr-operator
std::vector<auto> x=…;  // not in a template argument
票数 2
EN

Stack Overflow用户

发布于 2020-11-20 18:23:32

你的模板需要更多的信息来做你想做的事情。如果不使用“可疑”(应该避免使用reinterptret_cast<>)指针游戏,也很难做你想做的事情。使用宏会给我们一些语法上的甜头。

此示例使用引用以便于使用,修改为使用(或为指针添加suuport )应该非常容易。

代码语言:javascript
复制
#include <cstddef>   // offsetof()
#include <iostream>  // std::cout
#include <string>

template <typename _ClassT, typename _MemberT, size_t _Offset>
struct Base {
  void Process(const _ClassT& e) {
    std::cout << GetMemberRef(e);  // your code used printf(), but you shouldn't
                                   // assume the type of the inner member.
                                   // That's the whole point of this exercise,
                                   // isn't it?
    auto& tmp = GetMemberRef(e);
    std::cout << tmp;
  }

  // the name of access functions is quite verbose, but that's for 
  // demonstration purposes only.

  static const _MemberT& GetMemberRef(const _ClassT& e) {
    return *reinterpret_cast<const _MemberT*>(
        reinterpret_cast<const char*>(&e) + _Offset);
  }

  static _MemberT& GetMemberRef(_ClassT& e) {
    return *reinterpret_cast<_MemberT*>(reinterpret_cast<char*>(&e) + _Offset);
  }
};

// utility to make instantiation a bit easier to read and write...
// I don't think there is a way to do that without a macro.
#define MakeBase(type, member) \
  Base<type, decltype(type::member), offsetof(type, member)> {}

// test the code...

struct Test {
  std::string s;
};

struct Test2 {
  int value = 42;
};

int main() {
  Test t;
  t.s = "x";

  // declaration is a bit awkward, but there are no ways around that.      
  Base<Test, decltype(Test::s), offsetof(Test, s)> r;
  r.Process(t);

  // using MakeBase utility macro is quite clean, though. 
  auto x = MakeBase(Test2, value);
  x.Process(Test2{});
}
票数 -3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64932083

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档