如何编写“is_complete”模板?
回答这个问题后,我试图找到is_complete
模板在Boost库中,我意识到Boost.TypeTraits中没有这样的模板。为什么Boost库中没有这样的模板?它应该是什么样子?
//! Check whether type complete
template<typename T>
struct is_complete
{
static const bool value = ( sizeof(T) > 0 );
};
...
// so I could use it in such a way
BOOST_STATIC_ASSERT( boost::is_complete<T>::value );
上面的代码不正确,因为将 sizeof
应用于不完整的类型是非法的。什么是一个好的解决方案? 在这种情况下是否可以应用 SFINAE?
After answering this question I was trying to find is_complete
template in Boost library and I realized that there is no such template in Boost.TypeTraits. Why there is no such template in Boost library? How it should look like?
//! Check whether type complete
template<typename T>
struct is_complete
{
static const bool value = ( sizeof(T) > 0 );
};
...
// so I could use it in such a way
BOOST_STATIC_ASSERT( boost::is_complete<T>::value );
The code above is not correct, because it is illegal to apply sizeof
to an incomplete type. What will be a good solution? Is it possible to apply SFINAE in this case somehow?
Well, this problem couldn't be solved in general without violating the ODR rule, but there is there a platform specific solution which works for me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
Alexey Malistov 给出的答案只需稍作修改即可在 MSVC 上使用:
不幸的是,
__COUNTER__
预定义宏不是标准的一部分,因此它不适用于每个编译器。The answer given by Alexey Malistov can be used on MSVC with a minor modification:
Unfortunately, the
__COUNTER__
predefined macro is not part of the standard, so it would not work on every compiler.可能有点晚了,但到目前为止,还没有 C++ 11 解决方案同时适用于完整类型和抽象类型。
所以,你来了。
使用 VS2015 (v140)、g++ >= 4.8.1、clang >= 3.4,这可以正常工作:
感谢 Bat-Ulzii Luvsanbat: https://blogs.msdn.microsoft.com/vcblog/2015/12 /02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
使用 VS2013 (V120):
这个灵感来自互联网和 静态断言模板类型名 T 不完整?
It might be a bit late, but so far, no C++ 11 solution worked for both complete and abstract types.
So, here you are.
With VS2015 (v140), g++ >= 4.8.1, clang >= 3.4, this is working:
Thanks to Bat-Ulzii Luvsanbat: https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
With VS2013 (V120):
This one is inspired from the internets and static assert that template typename T is NOT complete?
恐怕您无法实现这样的
is_complete
类型特征。 @Alexey 给出的实现无法在 G++ 4.4.2 和 G++ 4.5.0 上编译:,使用 G++ 4.0.1 评估
is_complete::value
其中struct Foo;
不完整会产生true
,这比编译器错误更糟糕。T
在同一程序中可以是完整的,也可以是不完整的,具体取决于翻译单元,但它始终是相同的类型。因此,如上所述,is_complete
也始终是相同的类型。因此,如果您尊重 ODR,则不可能有
is_complete
根据使用位置评估不同的值;否则,这意味着您对 ODR 禁止的is_complete
有不同的定义。编辑:作为公认的答案,我自己破解了一个解决方案,该解决方案使用 __COUNTER__ 宏在每次
IS_COMPLETE< 时实例化不同的
is_complete
类型使用 /code> 宏。然而,对于 gcc,我一开始就无法让 SFINAE 工作。I'm afraid you can't implement such an
is_complete
type traits. The implementation given by @Alexey fails to compile on G++ 4.4.2 and G++ 4.5.0:On my Mac, with G++ 4.0.1 evaluating
is_complete<Foo>::value
wherestruct Foo;
is incomplete yields totrue
which is even worse than a compiler error.T
can be both complete and incomplete in the same program, depending on the translation unit but it's always the same type. As a consequence, as commented above,is_complete<T>
is always the same type as well.So if you respect ODR it is not possible to have
is_complete<T>
evaluating to different values depending on where it is used; otherwise it would mean you have different definitions foris_complete<T>
which ODR forbids.EDIT: As the accepted answer, I myself hacked around a solution that uses the
__COUNTER__
macro to instantiate a differentis_complete<T, int>
type everytime theIS_COMPLETE
macro is used. However, with gcc, I couldn't get SFINAE to work in the first place.解决此问题需要在特征模板的默认参数中执行计算,因为尝试更改模板的定义违反了 ODR 规则(尽管
__COUNTER__
和namespace {} 可以解决 ODR)。
这是用 C++11 编写的,但可以调整为在最近的 C++11 兼容编译器的 C++03 模式下工作。
在线演示。
默认参数在模板命名的地方进行计算,因此它可以根据上下文在不同的定义之间切换。每次使用时不需要不同的专业化和定义;您只需要一个用于
true
和一个用于false
。该规则在 §8.3.6/9 中给出,它同样适用于函数默认参数和默认模板参数:
但要注意,在模板中使用它几乎肯定会违反 ODR。在不完整类型上实例化的模板不得执行与在完整类型上实例化时不同的任何操作。我个人只希望将其用于
static_assert
。顺便说一句,如果您想走另一条路,并且 使用模板和重载实现
__COUNTER__
的功能。Solving this requires performing the computation in the default argument of the trait template, as attempting to change the definition of a template violates the ODR rule (although a combination of
__COUNTER__
andnamespace {}
can work around ODR).This is written in C++11 but can be adjusted to work in C++03 mode of a moderately recent C++11-compatible compiler.
Online demo.
The default argument is evaluated where the template is named, so it can contextually switch between different definitions. There is no need for a different specialization and definition at each use; you only need one for
true
and one forfalse
.The rule is given in §8.3.6/9, which applies equally to function default arguments and default template-arguments:
But beware, using this inside a template is almost sure to violate the ODR. A template instantiated on an incomplete type must not do anything differently from if it were instantiated on a complete type. I personally only want this for a
static_assert
.Incidentally, this principle may also be helpful if you want to go the other way and implement the functionality of
__COUNTER__
using templates and overloading.只是插话以表明对不相关问题的答案(不是我给出的)为
is_complete
模板提供了解决方案。答案就在这里。我不会将其粘贴在下面,以免错误地获得荣誉。
Just chiming in to signal that an answer (not given by me) to an unrelated question gives a solution for the
is_complete<T>
template.The answer is here. I'm not pasting it below in order to not mistakenly get credit for it.
我在标准中找不到任何内容可以保证不完整类型上的 sizeof 将产生 0。但是,它确实要求如果 T 在某个时刻不完整,但稍后在该翻译单元中完成,则对 T 的所有引用都引用到相同的类型 - 所以当我读到它时,即使 T 在调用模板的地方不完整,如果 T 在该翻译单元中的某个地方完成,则需要说它是完整的。
I can't find anything in the standard that guarantees that sizeof on an incomplete type will yield 0. It does require, however, that if T is incomplete at some point, but completed later in that translation unit, that all references to T refer to the same type -- so as I read it, even if T is incomplete where your template was invoked, it would be required to say it was complete if T is completed somewhere in that translation unit.
这是一个老问题,但建议的答案对于某些类型(例如函数引用类型或 cv 限定函数类型)无法正常工作。
现在这适用于类似函数的类型。
It's an old question, but the proposed answers doesn't work correctly for some types such as function reference type or cv-qualified function types.
Now this will work for function-like types.