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

use*_*520 7 c++ templates variadic-templates c++11

请考虑以下代码:

#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, int, char)>>(func);
    testfunc<int>(sfunc);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我明确指定了类型,因为(/sf/answers/2833325841/):

当参数包没有出现在参数声明的最后时,它是一个非推导的上下文.非推断的上下文意味着必须明确给出模板参数.

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, int, 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, Args..., 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, int, char)>’ is not derived from ‘const std::function<void(float, Args ..., char)>’
Run Code Online (Sandbox Code Playgroud)

现在,让我们做一个细微的变化-让我们删除int从我们当地的说法func,从而使模板参数包成为空:

#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, char) {};
    auto sfunc = static_cast<std::function<void (float, char)>>(func);
    testfunc<>(sfunc);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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

问题:

  1. 谁在第一种情况下是正确的?
  2. 如何实现预期的效果 - 即,如何显式指定(可能为空)参数包?

Yak*_*ont 7

我们可以阻止扣除:

template<typename... Args>
void testfunc(const block_deduction<std::function<void (float, Args..., char)>>& func)
Run Code Online (Sandbox Code Playgroud)

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

template<class T>
using block_deduction=typename tag_t<T>::type;
Run Code Online (Sandbox Code Playgroud)

现在Args...是在一个非演绎的背景下.

你可以做票友事情SFINAE并省略char然后测试该char在的结束Args...,但似乎矫枉过正.


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