c – 未作为最后一个参数传递时的模板参数包扣除

请考虑以下代码
#include <iostream>
#include <functional>

template<typename... Args>
void testfunc(const std::function<void (float,Args...,char)>& func)
{

}

int main(int argc,char* argv[])
{
    auto func = [](float,int,char) {};
    auto sfunc = static_cast<std::function<void (float,char)>>(func);
    testfunc<int>(sfunc);

    return 0;
}

我明确指定了类型,因为(https://stackoverflow.com/a/40476083):

When a parameter pack doesn’t appear last in the parameter
declaration,it is a non-deduced context. A non-deduced context means
that the template arguments have to be given explicitly.

MSVC成功编译它,而gcc和clang都拒绝代码

source_file.cpp: In function ‘int main(int,char**)’:
source_file.cpp:14:24: error: no matching function for call to ‘testfunc(std::function<void(float,char)>&)’
     testfunc<int>(sfunc);
                        ^
source_file.cpp:5:6: note: candidate: template<class ... Args> void testfunc(const std::function<void(float,Args ...,char)>&)
 void testfunc(const std::function<void (float,char)>& func)
      ^
source_file.cpp:5:6: note:   template argument deduction/substitution Failed:
source_file.cpp:14:24: note:   mismatched types ‘char’ and ‘int’
     testfunc<int>(sfunc);
                        ^
source_file.cpp:14:24: note:   ‘std::function<void(float,char)>’ is not derived from ‘const std::function<void(float,char)>’

现在让我们稍作改动 – 让我们从本地func中删除int参数,从而导致模板参数包变空:

#include <iostream>
#include <functional>

template<typename... Args>
void testfunc(const std::function<void (float,char)>>(func);
    testfunc<>(sfunc);

    return 0;
}

这一次,所有三个编译器都拒绝代码不正确.
使用http://rextester.com/l/cpp_online_compiler_gcc和本地Visual Studio安装进行测试.

问题:

>第一种情况谁是正确的?
>如何实现预期效果 – 即,如何明确指定(可能为空)参数包?

解决方法

我们可以阻止扣除:
template<typename... Args>
void testfunc(const block_deduction<std::function<void (float,char)>>& func)

template<class T>
struct tag_t{using type=T;};

template<class T>
using block_deduction=typename tag_t<T>::type;

现在Args ……处于非演绎的背景中.

你可以用SFINAE做更好的事情并省略char然后在Args的末尾测试char,但这看起来有点过分.

当gcc和clang不同意MSVC时,我会向甜甜圈打赌,MSVC不对.但我没有标准钻探确认.

相关文章

/** C+⬑ * 默认成员函数 原来C++类中,有6个默认成员函数: 构造函数 析构函数 拷贝...
#pragma once // 1. 设计一个不能被拷贝的类/* 解析:拷贝只会放生在两个场景中:拷贝构造函数以及赋值运...
C类型转换 C语言:显式和隐式类型转换 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译...
//异常的概念/*抛出异常后必须要捕获,否则终止程序(到最外层后会交给main管理,main的行为就是终止) try...
#pragma once /*Smart pointer 智能指针;灵巧指针 智能指针三大件//1.RAII//2.像指针一样使用//3.拷贝问...
目录&lt;future&gt;future模板类成员函数:promise类promise的使用例程:packaged_task模板类例程...