假设我有一个将要专门化的模板化函数,因此我真的不在乎基本实现。我可以做这样的事情吗?
template <typename T>
T dummy() {
assert(false);
return declval<T>();
}
当我尝试在visual-studio-2017中执行此操作时,出现链接错误:
在功能char const && __cdecl std::declval<char const >(void)
中引用的未解析的外部符号
char const __cdecl dummy<char const>()
(?? $ declval @ $$ CBD @ std @@ YA $$ QEBDXZ)
同样,该函数未被调用,但是我确实保存了指向它的指针。我可以改用return T{}
进行编译,但是即使T
没有默认构造函数,我也需要使用它。有什么办法可以解决这个问题?
答案 0 :(得分:3)
您可以通过不提供功能模板的定义来解决此问题。使用
template <typename T>
T dummy();
template <>
int dummy() { std::cout << "template <> int dummy()"; return 42;}
int main()
{
dummy<int>();
dummy<double>();
return 0;
}
因为dummy<double>();
不存在,所以会出现链接器错误,但是如果您注释掉它,则代码将编译,因为确实存在int
的特殊化。这意味着您不必担心会返回任何东西。
您可以使用
template <typename T>
T dummy() = delete;
与其提供一个定义,而不是提供一个链接器错误,您将得到一个“不错的”编译器错误,表明您正在尝试使用已删除的函数,而不是提供一个定义。这也允许您编写重载而不是专门化,这是可取的,因为在解决重载时不考虑专门化。对于您而言,这实际上是不可能的,因为您不带任何参数,但如果您这样做,则应考虑使用它。
答案 1 :(得分:1)
实例化dummy
会滥用std::declval<T>
,这是标准所不允许的。
请注意,仅省略return语句不是编译错误。如果调用dummy
,它只会导致UB。由于您确定永远不会调用dummy
,因此这对您不会造成任何问题。
但是,也许您想要做的是避免让编译器发出警告,指出控件已到达非void函数的末尾。毕竟,在非调试版本中,如果碰巧调用dummy
,则会到达函数 的结尾,因为assert
将消失。在这种情况下,我建议放在assert
之后:
throw std::logic_error("dummy should not be called");
现在,编译器应该看到该函数不可能不返回值而到达其主体结尾,因为它根本无法到达结尾。
如果dummy
实际上以某种方式被调用,而不是调用UB,这也使得程序实际上很可能崩溃。