【发布时间】:2015-10-02 07:36:51
【问题描述】:
在编写一个供个人使用的小型模板元编程库时,我遇到了一个有趣的问题。
由于我为某些元函数重用了一些偏特化,我决定将它们放在一个公共模板类下,并使用标签和嵌套偏特化来提供行为差异。
问题是我得到了(对我而言)荒谬的结果。这是一个展示我正在尝试做的事情的最小示例:
#include <iostream>
#include <cxxabi.h>
#include <typeinfo>
template <typename T>
const char * type_name()
{
return abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr);
}
template <typename... Args>
struct vargs {};
namespace details
{
template <typename K>
struct outer
{
template <typename Arg>
struct inner
{
using result = Arg;
};
};
}
struct tag {};
namespace details
{
template <>
template <typename Arg, typename... Args>
struct outer<tag>::inner<vargs<Arg, Args...>>
{
using result = typename outer<tag>::inner<Arg>::result;
};
}
template <typename T>
using test_t = typename details::outer<tag>::inner<T>::result;
int main()
{
using t = test_t<vargs<char, int>>;
std::cout << type_name<t>() << '\n';
return 0;
}
当使用 5.1.0 版本的 gcc 时,我得到 vargs<char, int> 作为输出,当使用 3.6.0 版本的 clang 时,我得到 tag。我的意图是让上面的代码打印char,所以我对这些结果感到很困惑。
上面的代码是合法的还是表现出未定义的行为? 如果它是合法的,那么根据标准的预期行为是什么?
【问题讨论】:
-
似乎 Clang 在某个过程中提出了
details::outer<tag>::inner<tag>。有趣,因为我不知道编译器如何混淆这些模板参数。 -
轻微修改会导致 Clang 中的 ICE:coliru.stacked-crooked.com/a/5ae1c222d3d9ad30
-
有趣的是,如果你完全用
inner的默认和特殊形式专门化outer<tag>,它会产生预期的输出:Coliru -
VS 2015 打印
char. -
与@jaggedSpire 类似的一个稍微简单但同样有效的更改是在尝试对其进行专门化之前为
outer<tag>::inner添加定义。请参阅Ideone
标签: c++ templates c++11 language-lawyer template-meta-programming