创建专用函数模板的最佳方法是什么?
有更好的方法来执行以下操作吗?
#include <iostream>
template <typename T>
T Bar();
template <>
int Bar<int>() { return 3; }
// Potentially other specialisations
int main()
{
std::cout << Bar<int>() << std::endl; // This should work
std::cout << Bar<float>() << std::endl; // This should fail
}
该解决方案的问题在于,它在(可以理解的)链接时失败,并出现“对 float Bar
的未定义引用”等问题。这可能会让其他开发人员感到困惑,因为他们可能怀疑未链接实现文件。
我确实知道另一个潜在的解决方案:
template <typename T>
T Bar() { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
当请求 Bar
时,这会导致编译器错误,这正是我想要的。但是,我担心从技术上讲,编译器可能会拒绝这一点,就像 gcc 拒绝 BOOST_STATIC_ASSERT(false) 一样,因为它知道无论模板参数如何,它都会失败,因为 sizeof(T)< /code>永远不能为零。
总之,我想知道是否:
- 还有另一种方法可以做到这一点。
- 我错了,
BOOST_STATIC_ASSERT(sizeof(T))
实际上在没有实例化的情况下不会失败。 - 唯一的方法是让它成为如上所述的链接器错误。
Is there a better way to do the following?
#include <iostream>
template <typename T>
T Bar();
template <>
int Bar<int>() { return 3; }
// Potentially other specialisations
int main()
{
std::cout << Bar<int>() << std::endl; // This should work
std::cout << Bar<float>() << std::endl; // This should fail
}
The problem with this solution is that it fails at (understandably) link time with "undefined reference to float Bar<float>()
" or the like. This can be confusing for other developers as they may suspect an implementation file is not being linked.
I do know another potential solution:
template <typename T>
T Bar() { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
This causes a compiler error when Bar<float>()
is requested, exactly what I want. However, I'm concerned that technically a compiler may reject this just as gcc rejects BOOST_STATIC_ASSERT(false)
because it knows that it will fail regardless of the template parameter, since sizeof(T)
can never be zero.
In summary, I want to know whether:
- There is another way to do this.
- I'm mistaken and
BOOST_STATIC_ASSERT(sizeof(T))
actually can't fail without instantiation. - The only way is to let this be a linker error as above.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这可行:
如果您害怕使用 0,您也可以使用尽可能大的大小:
This could work:
You could also use the highest size possible if you're afraid of using 0:
BOOST_STATIC_ASSERT(sizeof(T) == 0);
在模板实例化之前不允许失败,所以我就这样做。您每次都会触发BOOST_STATIC_ASSERT(false);
,这是正确的。其原因与两阶段名称查找有关。这本质上是这样的:编译模板时,它会被编译两次。编译器第一次看到模板时,它会编译除依赖于模板参数的表达式之外的所有内容,并且一旦模板参数已知,就会进行第二次编译,从而完全编译实例化。
这就是为什么
BOOST_STATIC_ASSERT(false);
总是失败:这里没有任何依赖项,并且断言会立即处理,就好像该函数根本不是模板一样。 (请注意,MSVC 没有实现两阶段查找,因此在实例化时会错误地失败。)相反,因为T
是依赖的 (§14.6.2.1),所以BOOST_STATIC_ASSERT(sizeof( T) == 0);
是依赖的,在模板实例化之前不允许检查。 (它总是会失败。)如果编译器试图深思熟虑并提前失败,那么它将是不合格的。你应该能够依赖这个东西。也就是说,如果恐惧战胜了你,那么真正让它等待是微不足道的:
这肯定会失败,而且编译器不可能提前正确地“智能”失败。
BOOST_STATIC_ASSERT(sizeof(T) == 0);
isn't allowed to fail until the template is instantiated, so I would just do that one. You are correct thatBOOST_STATIC_ASSERT(false);
triggers each time.The reason for this has to do with two-phase name lookup. This is, essentially, the following: when a template is compiled, it's compiled twice. The first time a compielr sees a template it compiles everything except the expressions dependent on template parameters, and the second compilation happens once the template parameter is known, compiling the instantiation fully.
This is why
BOOST_STATIC_ASSERT(false);
will fail always: nothing here is dependent and the assert is processed immediately, as if the function weren't a template at all. (Note that MSVC does not implement two-phase look-up, so this fails at instantiation, incorrectly.) Contrarily, becauseT
is dependent (§14.6.2.1),BOOST_STATIC_ASSERT(sizeof(T) == 0);
is dependent, and is not allowed to be checked until the template is instantiated. (Where upon it will always fail.)If a compiler tries to be thoughtful and fail it ahead of time, it would be non-conforming. You're suppose to be able to rely on this stuff. That said, if fear gets the best of you it's trivial to really make it wait:
This is both guaranteed to fail, and impossible for a compiler to correctly "smartly" fail ahead of time.
您可以执行如下操作:
这当然假设 T 没有具有给定名称的成员,因此您必须相应地选择“错误消息”(例如,通过违反命名约定)。
You could do something like the following:
This of course assumes, that T doesn't have a member with the given name, so you would have to choose your "error message" accordingly (e.g. by violating naming conventions).
将 static_assert 与 c++0x 一起使用,
这会在编译时引发错误。
对于c++ 98/2003,我们可以尝试这个
数组至少包含一个元素。所以编译器会抱怨。但错误消息可能无法显示发生的情况。
第一个不会是一个选择,因为它总是失败。
use static_assert with c++0x
this will raise an error when compiling.
For c++ 98/2003, we could try this
array at lest contains one element. So the compiler would complain. But the error message might be useless to show what happened.
The first wouldn't be a choice since it always fails.
如果您使用不带 -pedantic 的 gcc,则需要注意一点,在这种情况下,可能有
sizeof(T) == 0
- 当T< /code> 是一个零长度数组。
在这种情况下,您可以使用以下方法来解决它:
封装这个技巧可能会更好,这可以提高可读性,因为它表达了您的意图:
正如 GMan 所解释的,如果没有实例化,就像
sizeof( T) == 0
。然而,这个故事的寓意可能应该是始终使用 -pedantic 进行编译。There's a little caveat if you're using gcc without -pedantic, in which case it is possible to have
sizeof(T) == 0
- whenT
is a zero-length array.In this case you can work around it by using this instead:
It may be better to encapsulate this trick, which can improve readability because it expresses your intent:
As GMan explained, this can't fail without instantiation just like
sizeof(T) == 0
. However, the moral of this story should probably instead be always compile with -pedantic instead.