具有特殊功能的拉开功能类型

Posted

技术标签:

【中文标题】具有特殊功能的拉开功能类型【英文标题】:Pull Apart Function Type With Specialized Function 【发布时间】:2016-07-19 16:30:26 【问题描述】:

this question 的答案使用类模板来挑选函数类型:

template <typename T>
struct function_args ;

template <typename R, typename... Args>
struct function_args<R(Args...)> 
    using type = tuple<Args...>;
;

template <typename T>
using decltypeargs = typename function_args<T>::type;

当我研究这里所做的事情时,我试图重写function_args。我尝试使用一个函数来做到这一点,以消除对decltypeargs 模板的需要。但发现自己陷入了不正确的语法:

罢工>

template <typename T>
tuple<> myTry();

template <typename Ret, typename... Args>
tuple<Args...> myTry<Ret(Args...)>();

我希望调用decltype(myTry&lt;decltype(foo)&gt;()) 来获得tuple 类型,而不必调用decltypeargs&lt;decltype(foo)&gt;。有没有办法通过函数声明来做到这一点?

【问题讨论】:

你不能用函数模板做部分特化。但我想你想问点别的。我不太清楚。 @Arunmu 听起来你已经回答了我的问题。但我不确定如何改进措辞。我试图将函数的返回和参数分开,我需要使用专业化来做到这一点。我想用一个函数来做,但听起来我做不到。是不是更清楚了? 不确定您要做什么。 myTry() 只是打字多于不使用 - 你要解决的问题是什么? @JonathanMee 是的,更好,但恐怕答案还是一样的:) @Barry 我只是想用对我更有意义的术语(函数声明)重写你的答案。但似乎函数声明不能​​像这样专门化。所以我只需要更适应专门化的对象。 【参考方案1】:

使用函数,您可以重用以前的相同类型特征:

template <typename T>
function_args<T> myTry();

或者您可以使用函数重新实现相同的功能。你不能部分特化函数模板,但你可以重载:

namespace detail 
    template <class T> struct tag  ;

    template <class R, class... Args>
    tag<std::tuple<R, Args...>> myTry(tag<R(Args...)> );

    template <class R, class C, class... Args>
    tag<std::tuple<R, Args...>> myTry(tag<R(C::*)(Args...)> );        

    // etc.


template <typename T>
auto myTry()  return detail::myTry(detail::tag<T>); 

【讨论】:

tag 是干什么用的? @Cheersandhth.-Alf 这就是他用来破解部分专业化的方法。从根本上说,这是我的坏问题,显然正确的答案就是使用结构,这只是一个创造性的解决方法。 myTry 的 2 个定义在没有 tag 的情况下将是不同的重载。 @Cheersandhth.-Alf 是的,但链接问题的兴趣在于提取参数类型。 tag 允许我们在函数参数的上下文中执行此操作。如果您能想到在函数中执行此操作的更好方法,我会说您已经提出了更好的解决方案,并且应该将其发布为答案。【参考方案2】:
//------------------------ Machinery:
#include <tuple>

template< class Ret, class... Args >
std::tuple<Args...> m( Ret(Args...) );

//------------------------- Example:
#include <iostream>
#include <typeinfo>

void foo( double );

using namespace std;
auto main()
    -> int

    using Args_tuple = decltype( m( foo ) );
    cout << typeid( Args_tuple ).name() << endl;

【讨论】:

呃。这正是我无法将如何做的事情,就在一个功能中。当你第一次就能做对时,谁需要专业化? 我在这里问了一个后续问题:***.com/q/38482805/2642059 我想我一定不能很好地掌握decltype(m(foo)) 的工作原理,因为我无法将其扩展为使用方法。 【参考方案3】:

函数不能像那样专门化,但您不需要为此专门化函数。使用 gcc 6.1.1 测试:

#include <iostream>
#include <tuple>

template <typename T> struct my_try;

template <typename Ret, typename... Args>
struct my_try<Ret(Args...)> 

    std::tuple<Args...> operator()();

;

template<typename T>
auto MyTry()

    return my_try<T>()();



void foo(int, char);

int main()

    decltype(MyTry<decltype(foo)>()) t;

    int *a= &std::get<0>(t);
    char *b= &std::get<1>(t);

    return 0;

【讨论】:

哈哈,我想这确实是在一个函数中完成的。我希望 replace 用函数替换结构。 It sounds as though that's not possible though。也许你可以引用一些官方的说法来代替这个,指定函数不能被专门化? 我看不出替换结构有什么好处。编译后,它正好占用 0 位。 你完全正确。我只是觉得函数声明更舒服,所以我尝试使用它们。所以答案很简单:“你不能那样做。”但是,如果我们能在此处引用“因为我这么说”以外的其他内容,那就太好了。 @JonathanMee:函数可以完全特化,但不能部分特化。 很难为此提供标准的引用,因为它并没有真正说明函数模板不能部分特化的任何地方;它只是没有说它们 可以 (虽然它有 14.5.5 小节专门讨论类模板部分特化,但这与讨论显式模板特化的 14.7.3 小节和 14.8 节不同)。

以上是关于具有特殊功能的拉开功能类型的主要内容,如果未能解决你的问题,请参考以下文章

具有约束参数功能的类型类

24.编写一个Car类,具有String类型的属性品牌,具有功能drive; 定义其子类Aodi和Benchi,具有属性:价格型号;具有功能:变速; 定义主类E,在其main方法中分别创建Aodi和(

如何令自己所写的对象具有拷贝功能?

具有相同功能的活动和片段

使用类创建角色的 JavaScript 功能

装饰模式