首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >模板专门化的C++类型推导在空参数上失败

模板专门化的C++类型推导在空参数上失败
EN

Stack Overflow用户
提问于 2021-09-02 20:16:39
回答 2查看 69关注 0票数 1

我创建了一个模板类,其中的构造函数接受std::function对象。第一个模板参数表示该函数的返回值。第二个参数定义该函数的参数类型。

代码语言:javascript
复制
#include <functional>

//Base
template<class R, class Arg>
class Executor {
    public:      
        Executor(std::function<R(Arg)> function) 
            : mFunction(function)  
        {}

    private:
        std::function<R(Arg)> mFunction;
};

//Specialization1
template<class Arg>
class Executor<void, Arg> {
    public:      
        Executor(std::function<void(Arg)> function) 
            : mFunction(function)  
        {}

    private:
        std::function<void(Arg)> mFunction;
};

//Specialization2
template<class R>
class Executor<R, void> {
    public:      
        Executor(std::function<R()> function) 
            : mFunction(function)  
        {}

    private:
        std::function<R()> mFunction;
};

int testBase(float value) {
    return 5;
}

void testSpecialization1(float value) {}

int testSpecialization2() {
    return 22;
}

int main() {
    Executor executorBase{std::function(testBase)};
    
    Executor executorSpecialization1{std::function(testSpecialization1)};
    
    //Executor<int, void> executorSpecialization2{std::function(testSpecialization2)}; // Compiles
    Executor executorSpecialization2{std::function(testSpecialization2)}; // Doesn't compile. Uses Base. template<class R, class Arg>
}

在使用函数std::function时,请参见executorSpecialization2,编译器会报错:

代码语言:javascript
复制
main.cpp: In function 'int main()':
main.cpp:55:72: error: class template argument deduction failed:
   55 |     Executor executorSpecialization2{std::function(testSpecialization2)}; // Doesn't compile. Uses Base. template<class R, class Arg>
      |                                                                        ^
main.cpp:55:72: error: no matching function for call to 'Executor(std::function<int()>)'
main.cpp:7:9: note: candidate: 'template<class R, class Arg> Executor(std::function<R(Arg)>)-> Executor<R, Arg>'
    7 |         Executor(std::function<R(Arg)> function)
      |         ^~~~~~~~
main.cpp:7:9: note:   template argument deduction/substitution failed:
main.cpp:55:72: note:   candidate expects 1 argument, 0 provided
   55 |     Executor executorSpecialization2{std::function(testSpecialization2)}; // Doesn't compile. Uses Base. template<class R, class Arg>
      |                                                                        ^
main.cpp:5:7: note: candidate: 'template<class R, class Arg> Executor(Executor<R, Arg>)-> Executor<R, Arg>'
    5 | class Executor {
      |       ^~~~~~~~
main.cpp:5:7: note:   template argument deduction/substitution failed:
main.cpp:55:72: note:   'std::function<int()>' is not derived from 'Executor<R, Arg>'
   55 |     Executor executorSpecialization2{std::function(testSpecialization2)}; // Doesn't compile. Uses Base. template<class R, class Arg>
      |

它尝试使用基础版本。但是第二个参数当然是缺少的。如果我指定了模板参数,它就会编译。

那么为什么为executorSpecialization2选择基本模板呢?是否有可能在不需要传递模板参数的情况下对void使用类型推导?

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-02 20:39:51

当您像在Executor<int, float>中那样使用不带显式模板参数的名称Executor时,C++通常会试图弄清楚您所说的class template argument deduction (或CTAD)是什么意思。此过程不查看任何类模板专门化(部分或显式),只查看主模板。

主模板具有构造函数Executor(std::function<R(Arg)> function);。这足以为类型为std::function<int(float)>std::function<void(float)>的参数确定RArg。这只是为了确定ExecutorRArg是什么,然后应用专门化的常规考虑,所以第二个对象确实使用了Executor<void, Arg>专门化。

但在看到类型std::function<int()>时,它与std::function<R(Arg)>不匹配,因此CTAD失败。(尽管您可以拼写一个空的函数参数列表(void),意思与()相同,但这是一个特殊的规则,它需要一个非依赖的void类型,并且不适用于恰好具有void类型的模板参数。)

但是你可以通过写一个“演绎指南”来帮助CTAD:

代码语言:javascript
复制
template <class R>
Executor(std::function<R()>) -> Executor<R, void>;

除了主模板的构造函数之外,还使用了演绎指南。现在,std::function<int()>空类型的参数与演绎指南匹配,编译器确定R应该为int,并使用Executor<int, void>,这是由第二个部分专门化定义的。

看看它是如何工作的,on coliru

票数 3
EN

Stack Overflow用户

发布于 2021-09-02 20:34:15

int(void)仅在狭义情况下可用作int()

将其更改为:

代码语言:javascript
复制
template<class R, class... Args>
class Executor

并在正文中用Args...替换Arg

R, void专门化。

如果您需要class Executor<void, Arg>,请使用class Executor<void, Args...>

您的代码现在将编译一项工作。

(错误原因:隐式生成的扣减指南仅基于主要专业化认证。std::function(testSpecialization2)std::function<int()>,它与原始专门化的任何构造函数都不匹配。)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69036530

复制
相关文章

相似问题

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