gpt4 book ai didi

c++ - 模板、可变参数函数、通用引用和函数指针 : an explosive cocktail

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:28:54 25 4
gpt4 key购买 nike

考虑以下代码和 apply 函数:

// Include
#include <iostream>
#include <array>
#include <type_traits>
#include <sstream>
#include <string>
#include <cmath>
#include <algorithm>

// Just a small class to illustrate my question
template <typename Type, unsigned int Size>
class Array
{
// Class body (forget that, this is just for the example)
public:
template <class... Args> Array(const Args&... args) : _data({{args...}}) {;}
inline Type& operator[](unsigned int i) {return _data[i];}
inline const Type& operator[](unsigned int i) const {return _data[i];}
inline std::string str()
{
std::ostringstream oss;
for (unsigned int i = 0; i < Size; ++i)
oss<<((*this)[i])<<" ";
return oss.str();
}
protected:
std::array<Type, Size> _data;
// Apply declaration
public:
template <typename Return,
typename SameType,
class... Args,
class = typename std::enable_if<std::is_same<typename std::decay<SameType>::type, Type>::value>::type>
inline Array<Return, Size> apply(Return (*f)(SameType&&, Args&&...), const Array<Args, Size>&... args) const;
};

// Apply definition
template <typename Type, unsigned int Size>
template <typename Return, typename SameType, class... Args, class>
inline Array<Return, Size> Array<Type, Size>::
apply(Return (*f)(SameType&&, Args&&...), const Array<Args, Size>&... args) const
{
Array<Return, Size> result;
for (unsigned int i = 0; i < Size; ++i) {
result[i] = f((*this)[i], args[i]...);
}
return result;
}

// Example
int main(int argc, char *argv[])
{
Array<int, 3> x(1, 2, 3);
std::cout<<x.str()<<std::endl;
std::cout<<x.apply(std::sin).str()<<std::endl;
return 0;
}

编译失败:

universalref.cpp: In function ‘int main(int, char**)’:
universalref.cpp:45:32: erreur: no matching function for call to ‘Array<int, 3u>::apply(<unresolved overloaded function type>)’
universalref.cpp:45:32: note: candidate is:
universalref.cpp:24:200: note: template<class Return, class SameType, class ... Args, class> Array<Return, Size> Array::apply(Return (*)(SameType&&, Args&& ...), const Array<Args, Size>& ...) const [with Return = Return; SameType = SameType; Args = {Args ...}; <template-parameter-2-4> = <template-parameter-1-4>; Type = int; unsigned int Size = 3u]
universalref.cpp:24:200: note: template argument deduction/substitution failed:
universalref.cpp:45:32: note: mismatched types ‘SameType&&’ and ‘long double’
universalref.cpp:45:32: note: mismatched types ‘SameType&&’ and ‘float’
universalref.cpp:45:32: note: mismatched types ‘SameType&&’ and ‘double’
universalref.cpp:45:32: note: couldn't deduce template parameter ‘Return’

我不太清楚为什么会失败。在该代码中,我想:

  • 保持通用引用具有最通用的功能
  • 能够使用语法apply(std::sin)

那么我必须更改什么才能使其编译?

最佳答案

Several overloads exist功能std::sin ,并且您的函数模板无法推导出一个会产生完全匹配的函数(在大多数情况下,推导模板参数时不会考虑任何转换)。

首先,这些叠加层都不接受对其第一个(也是唯一一个)参数的引用。编译器告诉你这个,所以 ReturnSameType不能从参数类型推导出 f :

universalref.cpp:24:200: note:   template argument deduction/substitution failed:
universalref.cpp:45:32: note: mismatched types ‘SameType&&’ and ‘long double’
universalref.cpp:45:32: note: mismatched types ‘SameType&&’ and ‘float’
universalref.cpp:45:32: note: mismatched types ‘SameType&&’ and ‘double’

因此,第一步是更改您的 apply() 的签名函数模板:

[...] apply(Return (*f)(SameType, Args&&...), [...]
^^^^^^^^
No URef!

此外,SFINAE 正在消除函数模板的所有实例化,其中 Return未被推断为 int (您在 apply() 的实例上调用 Array<int, 3>):不幸的是,std::sin 的现有重载都没有有int作为返回类型。

您可以尝试将实例化更改为 Array<double, 3> ,但不幸的是,仅此一点无济于事,因为 C++11 标准的第 14.8.2/5 段指出:

The non-deduced contexts are:

— The nested-name-specifier of a type that was specified using a qualified-id.

— A non-type template argument or an array bound in which a subexpression references a template parameter.

— A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.

— A function parameter for which argument deduction cannot be done because the associated function argument is a function, or a set of overloaded functions (13.4), and one or more of the following apply:

— more than one function matches the function parameter type (resulting in an ambiguous deduction), or

— no function matches the function parameter type, or

the set of functions supplied as an argument contains one or more function templates.

由于需要支持整数类型的重载(这是 C+11 中的新内容,请参阅 26.8/11),您的库实现很可能确实定义了一个std::sin 的模板过载.这就是 stdlibc++ 的定义:

template<typename _Tp>
inline _GLIBCXX_CONSTEXPR
typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
double>::__type
sin(_Tp __x)
{ return __builtin_sin(__x); }

有很多方法可以离开这里,但您可能不喜欢它们。除了上述必要(但还不够)的更改外,您还需要显式转换 std::sin到所需的类型。我还将在此处删除 SFINAE 条件,因为它除了执行 SameType 之外没有做任何其他事情。等于Type :

// Declaration in the `Array` class
template <typename Return, class... Args>
inline Array<Return, Size> apply(
Return (*f)(Type, Args&&...),
const Array<Args, Size>&... args
) const;

[...]

// Example
int main(int argc, char *argv[])
{
Array<double, 3> x(1, 2, 3);
// ^^^^^^
// NOTICE
// THIS

std::cout<<x.str()<<std::endl;

std::cout<<x.apply((double(*)(double))std::sin).str()<<std::endl; // OK
// ^^^^^^^^^^^^^^^^^^^
// NOTICE THIS

return 0;
}

关于c++ - 模板、可变参数函数、通用引用和函数指针 : an explosive cocktail,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15031198/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com