当我这样做时,编译器不会抱怨; - )
// Myfile.h
#include <iostream>
#include <vector>
namespace std
{
template<> class vector<int>
{
public:
vector ()
{
std::cout << "Happy Halloween !!!\n";
}
};
}
有没有办法阻止类/函数模板的这种不合需要的特化?
我刚用std ::作为例子。我正在寻找的是一种防止这种情况发生在任何模板类中的方法。
答案 0 :(得分:11)
您所做的是在标准命名空间内专门化标准库类型。
除了一些记录的自定义点(std :: swap,std :: hash&lt;&gt;)或用户定义类型的特定约束特化(例如MySmartPtr<T>
)之外,这是违反的规范和结果是未定义的行为。
修改:此类规则违规没有强制性诊断。
为了让你的图书馆客户更加困难,你可以做到这一点:
namespace Public {
namespace Hidden { // DON'T TOUCH THESE!
template <typename> struct MyType { };
}
using Hidden::MyType;
}
现在,尝试在名称空间MyType<>
中专门化Hidden
将会失败。
答案 1 :(得分:8)
不,C ++语言没有提供一种通用机制,您可以通过该机制说“不允许对此模板进行专门化”。
但这可能无关紧要。对于您的代码已经使用的任何实例化,提供专业化的用户将违反一个定义规则,并且他们的程序可能会在火球中爆炸。
如果不使用库中的实例化,那么他们所做的并不重要。
这是其中一种情况,在C ++中你根本无法阻止你的用户自己在脚下射击,如果他们选择这样做,则责任就在他们身上。
答案 2 :(得分:5)
alias template无法专门化,并且具有类模板所需的行为。
template<class T>
struct my_class_implementation_which_should_not_be_used_directly
{
// impl
};
template<class T>
using my_class = my_class_implementation_which_should_not_be_used_directly<T>;
此外,您应该记录专门化的my_class_implementation_which_should_not_be_used_directly
会导致未定义的行为。现在你的图书馆用户不能意外地专门化my_class
,并且会直接警告那个丑陋的名字。
答案 3 :(得分:1)
编辑:
您可以使用C ++ 11中的enable_if来阻止模板的特化。但这是不切实际的。
#include <type_traits>
template<
typename real_t,
typename = typename std::enable_if<
std::is_floating_point<real_t>::value
>::type
>
struct check_t;
template<
typename real_t,
typename = typename
std::enable_if<
std::is_floating_point<real_t>::value,
check_t<real_t>
>::type
>
class vec_t
{
};
#if 1
template<>
class vec_t<int> {};
template<>
class vec_t<int,check_t<int>> {};
#endif
void test()
{
vec_t<float> vecf;
vec_t<int> veci;
}
main.cpp:26:16: error: no type named 'type' in 'struct std::enable_if<false, void>'
答案 4 :(得分:1)
防止此类行为的最佳方法是通过编码标准和代码审查。
在这种情况下,您不能强制编译器出错(除了使用其他答案中建议的解决方法),因为语言实际上允许这种行为,尽管它的实际用途可能会受到质疑。 问题是 - 您很可能希望/需要为多种类型提供通用行为(因此使用模板),但您需要为某些允许的类型(特别是std :: string)提供特定的实现< / p>
快速&amp;脏示例(它是一个函数,但同样适用于类)可能如下:
template<typename TData> TData GetData(std::string argument)
{
std::stringstream stream;
TData retVal;
stream.str(argument);
stream >> retVal;
return retVal;
}
然而,对于std :: string,这将失败,因为&gt;&gt;操作员将在第一个空格后停止。所以你可以提供专门的专业化。
template<> std::string GetData(std::string argument)
{
return argument;
}
答案 5 :(得分:-1)
有几种方法可以解决这个问题。您可以声明特定的特化而不定义它们。例如:
template<> struct MyStruct<int>;
这样,如果有人试图用int进行实例化,他们就会得到这种特化,并且由于有n个定义而无法编译。然后,您可以编写一个简单的宏来为您不希望专门化的所有类型执行此操作。
对于此反之,将定义设为空:
template<typename T> struct MyStruct{};
然后定义您计划支持的特定类型:
template<> struct MyStruct<int> {...};
template<> struct MyStruct<std::string> {...};
//etc...