我需要一个图像类模板,这将与不同数量的维度和不同格式的图像。我还想为1D,2D和3D图像定义不同的类模板专业化(只有这三个,其他人将离开未定义-所以他们不能使用)。
摘要代码:
enum image_format {R, G, B, RG, GB, RB, RGB}; // <--- Image format enumeration.
template<int dimensions, image_format format> // <--- Primary image class template.
class image; // Only few dimensions will be defined.
template<image_format format> // <--- Partial template specialization used here
class image<2, format> // to define image class for 2D images only.
{
private:
/* Class data here */
public:
image(int size_x, int size_y, char * bytes); // <--- 2D image constructor initializes
// object with given size and data.
};
template<image_format format, typename = typename std::enable_if // <--- SFINAE used here with unnamed template
<format == R or format == G or format == B>::type> // argument and accepts only R or G or B.
image<2, format>::image(int size_x, int size_y, char * bytes)
{
/* Code for R- or G- or B-formatted images only */
}
template<image_format format, typename = typename std::enable_if
<format == RG or format == GB or format == RB>::type>
image<2, format>::image(int size_x, int size_y, char * bytes)
{
/* Code for RG- or GB- or RB-formatted images only */
}
template<image_format format, typename = typename std::enable_if
<format == RGB>::type>
image<2, format>::image(int size_x, int size_y, char * bytes)
{
/* Code for RGB-formatted images only */
}
我可以在构造函数上使用模板专用化来为每种格式使用不同的代码,但是构造函数需要接受多个模板参数。(即image<2, R>
或image<2, G>
或image<2, B>
),第二个包含两个字母格式的图像,以此类推。如果要分离R、G和B构造函数,我需要在每个模板专用化中编写相同的代码,所以我想知道我是否可以使用SFINAE或这里的任何东西只写一次代码。
当我试图编译这段代码时,我得到了两个redefinition of image<2, format>::image
(我猜它来自多个构造函数实现)和/或too many template parameters in template redeclaration
(它来自构造函数实现模板中的额外参数,用于SFINAE的参数)。看起来我离实现我想要的不远了,但仍然有一些错误,我不知道是什么。
- 我知道 *
static_assert
* 或模板参数检查在这里就足够了,但是我想知道如果没有这些检查,只使用模板专门化和SFINAE是否可以做我想做的事情。*
2条答案
按热度按时间irtuqstp1#
这比您想象的要简单一些...但首先,您使用
std::enable_if
是错误的:如果你没有提供类型,那么它默认为void
,意味着 * 你所有的方法解析为相同的类型 *。打开你的编译器的警告,它会告诉你这类事情。下面是一种完成测试程序的方法:
这是因为:
= delete
不属于给定模板组合的公共帮助函数,这样它们就不是该类的一部分。这不是实现目标的唯一方法。还有其他方法。就我个人而言,我不确定你的类设计是我能接受的......但我不知道你的需求,也不知道你对它们有多大的控制力。
对于其他阅读,您可能想在谷歌上搜索“SFINAE”和“C++标记调度”。
pgky5nke2#
不能仅在定义中使用SFINAE。声明签名和定义签名应匹配。由于默认参数不是签名的一部分,请使用
使用
在C++17中,
if constexpr
可能会有所帮助:C++20中SFINAE的替代方法是使用
requires
进行约束: