我试图创建一个概念,缩小什么样的类可以与预定义的函数类型一起使用。我设法弄清楚如何将概念用于返回类型,但我仍然在努力不允许函数参数的隐式转换。特别是使用枚举。枚举定义为:
typedef enum GpioLevel {
LOW, HIGH
} GpioLevel;
字符串
目前,我的(有点混乱的)概念看起来如下:
template <typename P>
concept pinConcept = requires (GpioLevel level) {
P::Write(level);
requires std::same_as<std::underlying_type_t<decltype(level)>,std::underlying_type_t<GpioLevel>>;
P::Write(std::declval<GpioLevel>());
{P::GetLevel()} -> std::same_as<GpioLevel>;
};
型
那么一个应该遵循这个概念的类应该是:
class PinTemplate {
public:
static inline void Write(double level) {
std::cout<<"Writing "<<std::to_string(level) <<std::endl;
}
static inline GpioLevel GetLevel() {
return GpioLevel::HIGH;
}
};
型
这不应该被我的概念所接受,因为Write函数使用double而不是GpioLevel。然而,我运行得很好,有许多错误的数据:
template <pinConcept pin>
class SpiPinPort {
public:
void WriteData(){
pin::Write(GpioLevel::LOW);
// Below should actually not be allowed, but somehow it just casts it
pin::Write(5);
pin::Write('a');
}
};
int main()
{
SpiPinPort<PinTemplate> port;
port.WriteData();
}
型
这给了我一个输出:
- 写0.000000*
- 写5.000000*
- 写作97.000000*
然而,我希望在SpiPinPort示例化时出现编译错误,因为PinTemplate不遵守pinConcept概念。如果我将PinTemplate类的签名从double更改为GpioLevel,它确实会抛出一些错误(正如我所期望和希望的那样)。但我想限制允许模板类使用错误函数模板的可能性。
https://godbolt.org/z/v587aqcco
谢谢你
1条答案
按热度按时间9q78igpj1#
首先,让我们真实的浏览一下您的概念:
字符串
第二个要求:
型
decltype(level)
是GpioLevel
,所以这是检查相同类型的两个不同拼写是否相同。当然,它们是相同的。这个要求实际上没有做任何事情。第三个要求:
型
你很少需要在概念中使用
declval
,因为requires表达式允许你引入参数。在这种情况下,你已经有了一个GpioLevel
--level
。这已经是你在第一个需求中检查的内容。现在,有一个区别:
P::Write(level)
检查你是否可以用左值GpioLevel
调用Write
,P::Write(std::declval<GpioLevel>())
检查你是否可以用x值GpioLevel
调用Write
。但我真的怀疑这就是你要做的,或者这个区别在这里很重要。所以整件事可以是:
型
也就是说,
P::Write(level)
的需求并没有检查任何关于 types 的东西,而是检查 expression。你能用GpioLevel
调用P::Write
吗?现在,
GpioLevel
是一个无作用域的枚举。这意味着这是完全正确的:型
这是可以的,所以
PinTemplate::Write(LOW)
(尽管Write
取了double
)也是可以的,所以PinTemplate
满足pinConcept
。解决这个问题的最好方法是将
GpioLevel
更改为scoped enum:型
现在
GpioLevel
不能转换为double
,所以PinTemplate
不再满足pinConcept
。如果这不是一个选项,那么你唯一的其他方法是检查
P::Write
是一个具有特定类型的静态函数:型
这是更多的限制,因为现在
P::Write
不能是函数模板或具有默认函数参数。