Java和我猜C#(和其他人)支持Bounded Type Parameters,它允许我们限制模板类/函数中可以使用的类型。
我很好奇是否因为没有将有界类型的 native 支持添加到C ++中而有正式或其他原因?与模板当前处理方式有关?多继承问题?
我希望它非常有用。
答案 0 :(得分:1)
一个简单的事实是,之所以没有这个原因,是因为没有人想出一个可以让它在没有可怕副作用的情况下工作的功能。委员会已经在十年或更长时间内处理这个问题,最新的迭代仍然不适合。
此外,您引用的通用限制不是的有界类型。他们支持的唯一约束是“X继承自Y”,基本上,坦率地说,SFINAE std::is_base_of
涵盖了这种情况。 C ++需要更强大的功能,因为运行时继承是最不实用的功能之一。
答案 1 :(得分:1)
C ++有SFINAE,可以很容易地通过std :: enable_if来利用它。与type_traits一起,它实际上是IMO,比Java和C#具有的有界类型更强大。通过一些工作,您还可以制作一些很好的constexpr函数来为您测试这些东西。将它与一些宏结合起来,你就会看到像它一样的东西
#include <iostream>
#include <type_traits>
#define ENABLE_IF typename std::enable_if<
#define THEN(T) ,T>::type
class foo {};
class bar : public foo {};
template<class T, class U>
constexpr bool extends() {
return std::is_base_of<
typename std::remove_reference<U>::type,
typename std::remove_reference<T>::type
>::value;
}
template<class T>
ENABLE_IF extends<T, foo>() THEN(void) test(T&& v) {
std::cout << "T extends foo!!";
}
int main() {
test(bar{});
}
现在我不确定我会重新尝试这个但是它是可行的,截至目前我认为除了SFINAE难以调试之外没有任何问题
答案 2 :(得分:0)
大多数情况下,模板参数的约束应该不在类型上,而是在模板需要的操作上。 C ++以一种有点尴尬的方式做到这一点,仅仅是因为如果模板使用的操作不存在,则会收到错误消息。例如:
template <class T>
void show(T t) {
std::cout << t << std::endl;
}
如果使用未实现operator<<
的类型调用此模板函数,则会出现错误。 Java方法是使用print
方法定义接口,并要求用户传递实现该接口的类型的对象。 C ++方法不需要所有这些机制。
在C ++中执行此操作的问题在于,您可能会收到非常混乱的错误消息。通常,缺少的操作在另一个模板的某些低级部分中使用,并且错误消息与您编写的代码没有明确的关系。这是概念背后的驱动之一:模板的作者可以列出它使用的操作,并且传递其类型不支持这些操作的对象将导致在接口处违反概念,而不是在内部实现,因此您可能会收到更有用的错误消息。
答案 3 :(得分:0)
有界类型参数的目的是在提供的类型与所需的基类不匹配的情况下引发编译时错误,因此在C ++ 11及更高版本中,使用{ {1}}并为其提供static_assert
的值,如下所示:
std::is_base_of
其中template <typename T>
class C {
static_assert(std::is_base_of<SomeBoundedBaseClass, T>::value, "Bounded type parameter violation!");
//...the rest of the class C
};
是您要绑定类型参数SomeBoundedBaseClass
的类,以使其完全匹配或完全匹配。
还请注意,通过这种方式,您可以提及要显示为编译错误的任何自定义消息,因此与Java的内置功能相比,它甚至更具优势。不用说C ++更冗长,但是它也提供了更多的自由。