【发布时间】:2014-06-08 13:11:57
【问题描述】:
我正在为常见的“条件错误类型”问题(例如 this 昨天的问题)制定一个简单的解决方案。
在我的代码库中,我有一个模板来保存未实例化的模板并在以后实例化它们。像这样的:
template<template<typename...> class F>
struct lazy
{};
namespace impl
{
template<typename L , typename... ARGS>
struct lazy_instance;
template<template<typename...> class F , typename... ARGS>
struct lazy_instance<lazy<F>,ARGS...> : public identity<F<ARGS...>>
{};
}
template<typename L , typename... ARGS>
using lazy_instance = typename impl::lazy_instance<L,ARGS...>::type;
identity 是身份元函数。
这可以按如下方式使用:
using vector = lazy<std::vector>;
using int_vector = lazy_instance<vector,int>;
所以我想到的解决方案是这样包装条件的两个目标,并实例化条件的结果,所以只有选定的模板被实例化。为此,我修改了lazy 和impl::lazy_instance 以允许我们在lazy 实例化点传递模板参数:
template<template<typename...> class F , typename... ARGS>
struct lazy
{};
namespace impl
{
template<typename L , typename... ARGS>
struct lazy_instance;
template<template<typename...> class F , typename... ARGS , typename... IARGS>
struct lazy_instance<lazy<F,ARGS...>,IARGS...> : public identity<F<ARGS...>>
{};
}
请注意,在这种情况下,lazy_instance 也接受模板参数,但它们会被忽略。我已经这样做了,以便为两个用例提供相同的界面。
所以我们的主要问题,对潜在不正确类型的条件选择的评估可以如下实现:
using ok = lazy_instance<typename std::conditional<true,
lazy<foo,int>,
lazy<foo,bool>
>::type
>;
其中foo 是一个模板,其中bool 实例的格式不正确,例如:
template<typename T>
struct foo;
template<>
struct foo<int>
{};
它似乎有效,不是吗?伟大的。但几分钟后,我将布尔标志更改为false,令人惊讶的是它也有效!即使没有定义foo<bool> 特化!
元程序还有一个static_assert 来检查条件的评估是否成功:
static_assert( std::is_same<ok,foo<int>>::value , "Mmmmm..." );
当我将条件从 true 更改为 false 时,我更改了测试以查看那里发生了什么:
static_assert( std::is_same<ok,foo<bool>>::value , "Mmmmm..." );
元程序也通过了测试!即使有 foo<bool> 和 ok 的显式实例化,这应该是该实例的别名。
最后我检查了没有“foo<bool>没有匹配的特化”,直到我声明了一个ok类型的变量:ok anok;
我正在使用 C++11 模式 (-std=c++11) 的 CLang 3.4。我的问题是:这里发生了什么?这种行为是正确的还是 LLVM 错误?
编辑: Here 是在 ideone 运行的 SSCCE。它使用 GCC 4.8.1,但似乎具有相同的行为。
【问题讨论】:
-
只有在需要完整的对象类型时才会进行实例化。只需命名
foo<bool>不需要实例化。见 [temp.inst]/1 -
@dyp 这就是我的想法。但是对其进行 typedef 并不会实例化模板?
-
typedef 是否需要完整的类型?
typedef void my_void; -
@dyp mmm 好的。谢谢你的帮助。所以我误解了实例化规则
-
std::conditional的问题是过早地评估用作参数的元函数:std::conditional<b, fun0<arg>::type, fun1<arg>::type>::type而不是,比如说,std::conditional<b, fun0<arg>, fun1<arg>>::type::type
标签: c++ templates c++11 template-meta-programming llvm-clang