从特征获取常量或非常量引用类型

发布于 2024-08-28 20:22:41 字数 1290 浏览 9 评论 0原文

我正在编写一个函子 F,它接受 void (*func)(T) 类型的函数和 func 的参数 arg。

template<typename T>
  void F(void (*func)(T), WhatTypeHere? arg)
{
  func(arg);
}

然后函子 F 使用 arg 调用 func。我希望 F 不要复制 arg,只是将其作为引用传递。但是我不能简单地写“void F(void (*func)(T), T&)”,因为 T 可以是引用。所以我试图编写一个特征,它允许获得正确的 T 引用类型:

T -> T&
T& -> T&
const T -> const T&
const T& -> const T&

我想出了这样的东西:

template<typename T>
 struct type_op
{
 typedef T& valid_ref_type;
};

template<typename T>
 struct type_op<T&>
{
 typedef typename type_op<T>::valid_ref_type valid_ref_type;
};

template<typename T>
 struct type_op<const T>
{
 typedef const T& valid_ref_type;
};

template<typename T>
 struct type_op<const T&>
{
 typedef const T& valid_ref_type;
};


template<typename T>
  void F(void (*func)(T), typename type_op<T>::valid_ref_type arg)
{
  func(arg);
}

不起作用

void a(int x) { std::cout << x << std::endl; }
F(&a, 7);

这对于给出错误 : 类型“int&”的非常量引用的初始化无效从类型为 'int' 的临时变量传递 'void F(void (*)(T), typename type_op::valid_ref_type) [with T = int]' 的参数 2

如何使此特征发挥作用?

I am writing a functor F which takes function of type void (*func)(T) and func's argument arg.

template<typename T>
  void F(void (*func)(T), WhatTypeHere? arg)
{
  func(arg);
}

Then functor F calls func with arg. I would like F not to copy arg, just to pass it as reference. But then I cannot simply write "void F(void (*func)(T), T&)" because T could be a reference. So I am trying to write a trait, which allows to get proper reference type of T:

T -> T&
T& -> T&
const T -> const T&
const T& -> const T&

I come up with something like this:

template<typename T>
 struct type_op
{
 typedef T& valid_ref_type;
};

template<typename T>
 struct type_op<T&>
{
 typedef typename type_op<T>::valid_ref_type valid_ref_type;
};

template<typename T>
 struct type_op<const T>
{
 typedef const T& valid_ref_type;
};

template<typename T>
 struct type_op<const T&>
{
 typedef const T& valid_ref_type;
};


template<typename T>
  void F(void (*func)(T), typename type_op<T>::valid_ref_type arg)
{
  func(arg);
}

Which doesn't work for example for

void a(int x) { std::cout << x << std::endl; }
F(&a, 7);

Giving error:
invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int’ in passing argument 2 of ‘void F(void (*)(T), typename type_op::valid_ref_type) [with T = int]’

How to get this trait to work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

唔猫 2024-09-04 20:22:41
template<class T>
struct forwarding { typedef T const& type; };
template<class T>
struct forwarding<T&> { typedef T& type; };

template<typename T>
void F(void (*func)(T), typename forwarding<T>::type arg) {
  func(arg);
}

void a(int x) { std::cout << x << std::endl; }
int main() {
  F(&a, 7);
}

您的映射很接近,您实际上希望 T 映射到 T const&同样:

T        -> T const&
T&       -> T&
T const& -> T const&

请注意,参数类型为 T const 的函数的签名为 T! const 是一个实现细节:

void f(int const);
typedef void F(int); // typedef of function type
F* p = &f; // no error! f's signature doesn't include const
template<class T>
struct forwarding { typedef T const& type; };
template<class T>
struct forwarding<T&> { typedef T& type; };

template<typename T>
void F(void (*func)(T), typename forwarding<T>::type arg) {
  func(arg);
}

void a(int x) { std::cout << x << std::endl; }
int main() {
  F(&a, 7);
}

Your mapping was close, you actually want T mapped to T const& too:

T        -> T const&
T&       -> T&
T const& -> T const&

Note that functions having a parameter type of T const have a signature of T! The const is an implementation detail:

void f(int const);
typedef void F(int); // typedef of function type
F* p = &f; // no error! f's signature doesn't include const
素手挽清风 2024-09-04 20:22:41

您所需要做的就是删除引用:

template<typename T> struct remove_reference { typedef T type; };
template<typename T> struct remove_reference<T&> { typedef T type; };

然后再次添加它,如下所示:

remove_reference<T>::type&

您的函数应声明如下:

template<typename T>
void F( void (*func)(T), const typename remove_reference<T>::type& arg )
{
  func(arg);
}

All you need is to remove a reference:

template<typename T> struct remove_reference { typedef T type; };
template<typename T> struct remove_reference<T&> { typedef T type; };

Then add it again as follows:

remove_reference<T>::type&

Your function should be declared as follows:

template<typename T>
void F( void (*func)(T), const typename remove_reference<T>::type& arg )
{
  func(arg);
}
东风软 2024-09-04 20:22:41

我的想法有点模糊,但我认为 boost(可能是 boost::bind)通过仅提供 const T& 特征并需要使用 ref(x)< 来解决这个问题/code> 指示非常量引用。

It's a bit vague in my mind, but I think that boost (maybe boost::bind) solves this by only providing const T& traits, and requiring the use of ref(x) to indicate a non-const reference.

黑凤梨 2024-09-04 20:22:41

您还可以使用 add_reference来实现您需要的类型映射。

You could also use add_reference from Boost.TypeTraits to achieve the type-mapping you need.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文