用于返回相应类型的"zero"的 C++ 函数
c++ function to return "zero" of the appropriate type
我正在尝试编写一个zero()模板函数,该函数将始终返回适当类型的零。这对于基类型来说是微不足道的,但我希望用户定义类型也有类似的行为(可以提供它们自己的重载)。例如
auto i = zero<int>() // i is an in
auto d = zero<double>() // d is a double
auto m = zero<Matrix2d>() // m is a Matrix2d with all elements initialized to zero.
我有这个:
template <typename T>
T zero() {
return T{}*0; // Clearly not correct for all types, but known incorrect cases should be specialized
}
template <>
int zero<int>() { return 1; } // intentionally wrong for testing
但调用
cout << zero<int>() << endl;
输出0,表示没有调用专门化。我做错了什么?
*注意:这个用例类似于std::accumulate,但是假设起始值总是0,并且我们不想要求用户传递该值。
更新正如一些评论者所指出的,这在Ideone中是可行的。那么我的具体实现就会破坏它。我:
zero.h:
template <typename T>
constexpr T zero() {
return T{}*0;
}
zero.cpp:
#include "zero.h"
template <>
constexpr int zero<int>() { return 1; }
main.cpp:
#include <iostream>
#include "zero.h"
using namespace std;
int main(int argc, char **argv) {
cout << "int: " << zero<int>() << endl;
}
永远不要使用模板函数特化。好吧,几乎从来没有。
template<class T>struct tag_t{};
template<class T>constexpr tag_t<T> tag{};
这允许我们将类型作为值传递。
namespace utility{
template<class T>
T zero(){ return zero(tag<T>);}
template<class T>
T zero( tag_t<T> ) { return T{}*0; }
}
现在要添加对默认实现不支持的特定类型的支持,只需在X
的名称空间中覆盖zero(tag_t<X>)
(或者在std
或内置类型的类型中覆盖utility
)。
namespace math{
struct matrix2d; // define it
inline matrix2d zero( tag_t<matrix2d> ){ return matrix2d::zero; }
}
ADL将找到正确的零,如果你utility::zero<X>()
。
模板函数的专门化既不像模板类型的重载,也不像模板类型的专门化。它是脆弱的,它的规则是独一无二的;它很少是任何问题的最佳解决方案。避免它。
作为模板函数专门化是脆弱的,它并不奇怪我的一些细节没有显示打破了你的例子:代码张贴在OP并不明显打破天真转录时。这仍然是一个坏主意:除了脆弱性之外,它还迫使在名称空间bob中编写代码的人退出该名称空间,在其名称空间中添加专门化0,然后再回到名称空间bob。在这样做的时候,0的基本专门化必须是可见的,这会干扰依赖关系。
避免在".cpp"文件中使用模板。一些有用的参考资料。
尝试将所有内容移到头文件中:
zero.h:
template <typename T>
T zero() {
return T{}*0;
}
template <>
int zero<int>() { return 1; }
并删除 0 .cpp.
<标题>编辑:如果你正在使用Visual Studio,这可能会很有用:
标题>在Visual Studio . net 2003中进行的编译器一致性工作也会产生此错误。对于代码将在Visual Studio . net 2003和Visual Studio . net版本的Visual c++中有效,请删除模板<>.
"用例类似于std::accumulate
,但想象起始值始终为零,我们不想要求用户传递该值。"
碰巧的是,我的工具箱里正好有这个
template <typename FwdIter>
inline auto accumulate(FwdIter begin, FwdIter end)
-> typename std::iterator_traits<FwdIter>::value_type
{
return std::accumulate(begin, end,
typename std::iterator_traits<FwdIter>::value_type());
}
相关表达式是typename std::iterator_traits<FwdIter>::value_type()
,它计算给定迭代器类型的零值。您需要typename
,因为value_type
是依赖类型。
使用T
类型的默认构造函数或使用0
参数:
template <class T>
T zero()
{
return T() /* or T(0)*/;
}
- 如何在 Boost.Asio 中使用 Zero-copy sendmsg/receive
- 将"模板<类型名 T>zero()"扩展/专用为可调用的"T"
- Raspberry Pi Zero W 上的 OpenCV - 浮点异常
- C++ OpenCV Randu 函数抛出'Integer division by zero'
- 为什么我的代码在"decrease to zero"问题中被时间超过了
- "ndk-build finish with non-zero exit value 2" 在编译文本仙女项目时
- Epoll zero recv() and negative(EAGAIN) send()
- CreateCompatibleDC(IntPtr.Zero) returns IntPtr.Zero
- QT5.10.1交叉编译为Raspberry Pi Zero W使用EGLF而不是XCB
- Windows到Raspberry Pi Zero串行问题
- C++ Zero-Initialization
- Win32 CreateThread() Arguments Zero'ed?
- 无锁"decrement if not zero"
- 当我有多态指针时使用"rule of zero"
- 为什么 std::regex_match 不支持 "zero-length assertions" ?
- 如何修复'Size of list( a class) is unknown or zero error'和"声明语法错误"?
- 我多么应该将空指针传递给c ++函数,就像C#中的IntPter.Zero一样
- 为什么在破坏函数函数中fstream Zero ernno
- c++ static_cast returns zero
- 抑制来自 cout 的"minus zero"