为仅具有operator/定义的类型T创建一个模板<T>

3
我想为类型定义一个template<T>,但我必须确保只有定义了operator/operator+的类型才能被传递给T
这是因为我希望能够获取它们中的两个(类型相同)的插值值,例如:
template<class T>
class Key final : public KeyBase{
public: //to keep the example simple
    //unsigned timeMS; <-- iherited from KeyBase
    T value;

public:
    Key(unsigned timeMS, const T &value) 
        : KeyBase(timeMS), value(value){}
    T inline getValue(){ return value; }
};

Key<float> start = {10, 5.0f};
Key<float> end = {15, 3.0f};
float ratioAtTime12 = 12 / (end.timeMS - start.timeMS);
float valueAtTime12 = start.value + (end.value - start.value) * ratio;

//Point2D is my own custom type that have operator+, - and / defined
Key<Point2D> start2 = {10, Point2D(10, 15)};
Key<Point2D> end2 = {15, Point2D(111, 6)};
...

Key<Character> start3 = {10, Character("Alan")}; //SHOULD generate an error
//because my custom Character type has no operator+, - or / defined!

对于简单类型如floatint等,没问题。但如果使用复杂类型T 且它们没有定义operator/operator+,该怎么办呢?


2
如果在未定义该运算符的类实例上使用它,则会出现编译错误,因此类型会隐式受到限制。 - Géza Török
如果这些运算符没有被定义,你希望它做什么? - Mark B
@GézaTörök 我同意。但是我希望在创建这样的对象时立即收到错误提示(从我的角度来看,甚至声明它都是无意义的),而不是等待操作员使用它。 - PolGraphic
@MarkB 我想要产生一个编译时的错误来达到最佳效果。 - PolGraphic
1个回答

6

如果你想要一个不包含由ADL或类似方式发现的许多运算符的良好错误消息,你可以定义特性:

template <typename, typename=void>
struct isAddable : std::false_type {};

template <typename T>
struct isAddable<T, decltype(void(std::declval<T>() + std::declval<T>()))>
    : std::true_type {};

template <typename, typename=void>
struct isDividable : std::false_type {};

template <typename T>
struct isDividable<T, decltype(void(std::declval<T>() / std::declval<T>()))>
    : std::true_type {};

...并使用静态断言。

static_assert( isAddable<T>{} && isDividable<T>{}, "Invalid T!" );

或者,要获取更具体的信息:

static_assert( isAddable<T>{}, "T not addable!" );
static_assert( isDividable<T>{}, "T not dividable!" );

演示


您还可以使用方便的宏来定义此类特征。

#define VAL std::declval<T>()

#define DEF_TRAIT(name, expression)                                  \
template <typename, typename=void> struct name : std::false_type {}; \
template <typename T>                                                \
struct name<T, decltype(void(expression))> : std::true_type {};

DEF_TRAIT(isDividable, VAL / VAL)
DEF_TRAIT(isAddable, VAL + VAL)

演示


太棒了 :) 感谢您提供详细的答案和示例,先生。 - PolGraphic
这个检查是否T / TT + T是有效的,但当重载不是为两个相同类型的对象而制作时,它会失败。 - David G
@0x499602D2 不相关。问题陈述了“因为我想要能够获取两个相同类型的插值值”, - Columbo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接