有没有办法为模板类提供默认值?
例如假设我有一个类
TimeSeries
,它是模板化的。 我有一个名为 Foo()
的函数,它返回 T
。
template <typename T>
class TimeSeries
{
T foo();
}
我想要
Foo()
进行一些计算并返回 T
类型的内容。但如果不能,我希望它给出一个默认值。如果 T
是 double
,我希望它是 NaN
。如果 T
是 int
,我希望它是 0
。
TimeSeries<double> t;
t.foo(); // returns NAN
TimeSeries<int> t;
t.foo(); // returns 0
我如何实现这一目标?
一个糟糕的解决方案是让
Foo()
采用默认值。
template <typename T>
class TimeSeries
{
T foo(T defaultValue)
{
T ret;
// if OK
ret = computeValue();
// if not OK
ret = defaultValue;
return ret;
}
}
因此默认值是
0
或 NaN
,具体取决于用户。
或者我一开始就要求有缺陷的设计?
编辑- 一个合乎逻辑的问题是问如果
T
不是 int
或 double
会发生什么。默认值到底意味着什么?
我使用
TimeSeries
、T
的方式并不完全是通用类型。只能是 int
、double
和 string
中的 1 个。
我想过简单地编写 3 个独立的 TimeSeries
类,但这似乎是一个有缺陷的方法。
我对其他想法持开放态度。
您可以声明以下模板,
default_value<>
:
template<typename>
struct default_value;
然后,使用名为
int
的成员提供 double
和 value
的完整专业化,该成员提供所需的默认值:
template<>
struct default_value<int> {
static constexpr int value = 0;
};
template<>
struct default_value<double> {
static constexpr double value = NaN;
};
然后,在您的
foo
函数模板中,您可以简单地返回该值:
return default_value<T>::value;
这取决于
T
。
从 C++14 开始,您可以使用 变量模板:
template <class T> constexpr T default_value = {};
template <>
constexpr double default_value<double> = std::numeric_limits<double>::quiet_NaN();
template <typename T> class TimeSeries
{
auto foo() -> T
{
T ret;
if (condition)
return ret;
else
return default_value<T>;
}
};
或者我一开始就要求有缺陷的设计?
就我而言,这是一个有效的要求。
我认为有两种方法可以满足该要求。
您可以使用
default_value
中建议的方法另一个答案。
std::optional
。
如果您无法选择使用 C++17,则可以通过将返回值更改为
std::optional
,以一种不太复杂的方式模拟 std::pair<boo, T>
,并理解返回值的 first
已设置如果计算不成功,则为 false
;如果计算成功,则为 true
。
就我个人而言,我更喜欢第二种解决方案。它不依赖哨兵值。它以清晰明确的方式捕获计算是否成功的状态。
我也有类似的问题。就我而言,我只是想初始化模板参数类型的变量,而不是作为默认返回。我无法使上述任何方法发挥作用。我使用了 @jfMR 建议的变体。 (作为格式化的单独答案发布)。就我而言,我还想支持原始类型和对象类型。
我使用第二个模板参数来提供一个可调用结构,生成我需要的默认值。完整样本:
#include <stdio.h>
#include <string>
#include <iostream>
struct DefaultInt
{
int operator () () const { return 42; }
};
struct DefaultChar
{
char operator () () const { return 'z'; }
};
struct DefaultString
{
std::string operator () () const { return std::string("waldo"); }
};
template<class TP, class TPDefaultValue> class DemoWrapper
{
public:
DemoWrapper()
{
TPDefaultValue valueFactory;
_wrap = valueFactory();
}
DemoWrapper(TP wrap) : _wrap(wrap)
{}
void Print() { std::cout << _wrap << std::endl; }
private:
TP _wrap;
};
int main(int argc, const char *argv[])
{
std::string demoString("Thanks for all the fish");
const int demoInt = 13;
DemoWrapper<int, DefaultInt> dw1(demoInt);
DemoWrapper<int, DefaultInt> dw2;
DemoWrapper<std::string, DefaultString> dw3(demoString);
DemoWrapper<std::string, DefaultString> dw4;
dw1.Print();
dw2.Print();
dw3.Print();
dw4.Print();
}
输出:
13
42
Thanks for all the fish
waldo