专门化自动跟踪返回类型

时间:2015-07-21 10:44:46

标签: c++ templates

我有一些代码使用两种不同类型的颜色,每通道8位,每通道16位,每个由结构表示。为了有效地重用我的代码,我有一个模板函数,可以用它们进行一些渲染。因此,我想要一个模板化的函数来获取我的颜色通道的最大值。

我最初的尝试看起来像这样。我只展示了8 bpc

的专业化
struct Pixel8
{
   unsigned char r;
   unsigned char g;
   unsigned char b;
};
#define PIXEL8_MAX 255

template <class PIXEL>
auto getMax( ) -> decltype( PIXEL::r )
{
   static_assert( sizeof(PIXEL) > 0, "getMax can only be called with a pixel type." );
}
template <>
auto getMax<Pixel8>( ) -> decltype( Pixel8::r )
{
   return PIXEL8_MAX;
}

这不能用Visual Studio 2012编译。我收到错误

1&GT;错误C2785:''unknown-type'getMax(void)'和'char getMax(void)'有不同的返回类型 1 GT;看到'getMax'的声明

对我来说,我觉得这应该有效,但我找不到任何例子。在Specialize function template with decltype trailing return type还有一个类似的问题,但是这里的返回类型对于每个专业化都是相同的。

我找到了一个解决方法,我将其作为答案发布,以便其他人可以受益。但是它不是很透明,所以如果有人能告诉我上面的代码是否有效且这是VC ++不兼容还是无效,那么为什么以及如何使其有效呢?

3 个答案:

答案 0 :(得分:0)

这是获取所需行为的解决方法。它依赖于以下事实:在不使用decltype的情况下,还有另一种在C ++中定义类型的方法。这是使用typname。

在这种情况下它的主要用途如下,想象两个类和两个函数

class MyClass
{
public:
    class MyThing
    {
    };
};

class MyOtherClass
{
public:
    static int MyThing;
}

template< class T >
void func1( T something )
{
    typename T::MyThing thing;
}

template< class T >
void func2( T something )
{
    T::MyThing = 5;
}

如果我们将任一类作为模板参数T传递,那么T :: MyThing将是MyClass的类型,而MyOtherClass是静态int。这些完全不兼容,因此我们使用typename来分隔它们。 在func1中,我们使用typename来声明T :: MyThing是一个类型。我们可以传入一个MyClass对象。在func2中我们省略了typename,因此T :: MyThing被解释为变量,我们可以传入MyOtherClass。如果没有typename,就无法判断T :: MyThing是类型还是静态变量。

另请注意,typename可以引用typdef以及内部类。因此,如果我们创建一个模板化的类或包含类型的typedef的结构,我们可以使用typename访问该类型。

template<class PIXEL>
struct pixTypes
{
};

template<>
struct pixTypes<Pixel8>
{
    typedef char type;
};

template <class PIXEL>
auto getMax( ) -> typename pixTypes<PIXEL>::type
{
    static_assert( false, "getMax can only be called with a pixel type." );
}
template <>
auto getMax<Pixel8>() -> typename pixTypes<Pixel8>::type
{
    return PIXEL8_MAX;
}

所以现在我们从一个typename中获取我们的返回类型,该类型引用一个专门模板化结构中的typedef。

这似乎是一种围绕一切的复杂方式,但它确实在Visual Studio 12上编译。

答案 1 :(得分:0)

尝试使返回类型取决于模板参数类型:

struct Pixel8
{
    char r;
    char g;
    char b;
};

template<typename T>
struct ColourType
{
    typedef decltype(T::r) type;
};

#define PIXEL8_MAX 255

template <class PIXEL>
typename ColourType<PIXEL>::type getMax()
{
    static_assert(false, "getMax can only be called with a pixel type.");
}
template <>
ColourType<Pixel8>::type getMax<Pixel8>()
{
    return PIXEL8_MAX;
}

答案 2 :(得分:0)

使用宏来定义常量,如本问题的代码

#define PIXEL8_MAX 255

......不理想。

此外,定义与使用的类型冲突。 char不保证具有该最大值,并且大多数实现默认情况下不具有该最大值。您可以将Byte类型定义为unsigned char,但即使如此,您也不能保证8位,并且应该检查它。

标准库提供 numeric_limits 类模板来处理最大值等。:

#include <limits>       // std::numeric_limits

#define STATIC_ASSERT( e ) static_assert( e, #e )

using Byte = unsigned char;
int const bits_per_byte = std::numeric_limits<Byte>::digits;
STATIC_ASSERT( bits_per_byte == 8 );

struct Pixel8
{
    Byte r;
    Byte g;
    Byte b;
};

template< class Pixel >
constexpr auto getMax() -> decltype( Pixel::r )
{
    return std::numeric_limits<decltype( Pixel::r )>::max();
}

#include <iostream>
using namespace std;

auto main() -> int
{
    cout << +getMax<Pixel8>() << endl;
}