第三次编辑: 今天我收到了来自VS支持的电子邮件,说明它已知的问题,已在VS2017中修复。所以,我会暂时坚持我的解决方法。
我正在研究事件系统,我想使用一些元编程来节省打字。这是代码:
struct foo { using type = int; };
struct bar { using type = char; };
template<typename... Types> struct TypeList {};
//This and getScript are simplified, in reality the involve messier templates...
template<typename ReturnType>
struct ReqBuilder
{
using proxy = ReturnType(*)(void*, bool);
// ...
};
template<typename scriptType>
using getScript = ReqBuilder<scriptType>;
template<typename List, template<typename> typename Wrap> struct WrapTypeList_impl {};
template<typename...Ts, template<typename> typename Wrap> struct WrapTypeList_impl<TypeList<Ts...>, Wrap>
{
using type = TypeList<Wrap< Ts>...>;
};
template<typename List, template<typename> typename Wrap>
using WrapTypeList = typename WrapTypeList_impl<List, Wrap>::type;
//Use typedef
using list1 = TypeList<getScript<foo>, getScript<bar>>;
//Write it manually
using list2 = TypeList<ReqBuilder<foo>, ReqBuilder<bar>>;
//Use wrapper to wrap each element of typelist
using list3 = WrapTypeList<TypeList<foo, bar>, getScript>;
目标是将所有三个列表结果放在同一个TypeList中。此代码已经过简化,实际上 getScript 可以提供更多功能,而且实际上非常有用。对于包含更多typedef的 ReqBuilder 也是如此。因此, list3 应该比 list1 或 list2 更容易编写。
有更多的getScript,类似ReqBuilder的类以及嵌套类型列表的扁平化。 即使是复杂类型,也可以轻松编写所有可能事件的列表。
以上代码有效 - 所有列表都相同。问题是在嵌套类型上专门化(我想要):
template<typename scriptType>
using getScript = ReqBuilder<typename scriptType::type>;
然后我在WrapTypeList_impl::type=...
行发现了以下错误:
Error C2938 'getScript<unknown-type>' : Failed to specialize alias template
我真的不知道这意味着什么,但它可能与包扩展有关,因为当我添加这个专业化时:
template<typename A,typename B, template<typename> typename Wrap>
struct WrapTypeList_impl<TypeList<A,B>, Wrap>
{
using type = TypeList<Wrap<A>,Wrap<B>>;
};
然后它甚至适用于嵌套类型。那么,有没有人知道如何让这个工作吗?
我正在使用Visual Studio 2015 Comunnity版。更令人费解的是,使用智能感知 - 将鼠标悬停在列表上会显示他们已在同一个TypeList中解析,甚至std::is_same<list1,list3>::value
在悬停时显示true
。但编译器出于某种原因不同意。
编辑:添加了导致错误的完整代码
#include <algorithm>
struct foo { using type = int; };
struct bar { using type = char; };
template<typename... Types> struct TypeList {};
//This and getScript are simplified, in reality the involve messier templates...
template<typename ReturnType>
struct ReqBuilder
{
using proxy = ReturnType(*)(void*, bool);
// ...
};
template<typename scriptType>
using getScript = ReqBuilder<typename scriptType::type>;
template<typename List, template<typename> typename Wrap> struct WrapTypeList_impl {};
template<typename...Ts, template<typename> typename Wrap> struct WrapTypeList_impl<TypeList<Ts...>, Wrap>
{
using type = TypeList<Wrap<Ts>...>;
};
template<typename List, template<typename> typename Wrap>
using WrapTypeList = typename WrapTypeList_impl<List, Wrap>::type;
using list1 = TypeList<getScript<foo>, getScript<bar>>;
using list2 = TypeList<ReqBuilder<typename foo::type>, ReqBuilder<typename bar::type>>;
using list3 = WrapTypeList<TypeList<foo, bar>, getScript>;
int main()
{
constexpr bool A = std::is_same<list1, list2>::value;
constexpr bool B = std::is_same<list1, list3>::value;
constexpr bool C = std::is_same<list2, list3>::value;
static_assert(A, "list1 != list2");
static_assert(B, "list1 != list3");
static_assert(C, "list2 != list3");
}
Erorrs:
1> Main.cpp
1>Main.cpp(23): error C2938: 'getScript<unknown-type>' : Failed to specialize alias template
1> Main.cpp(31): note: see reference to class template instantiation 'WrapTypeList_impl<TypeList<foo,bar>,getScript>' being compiled
1>Main.cpp(23): error C3546: '...': there are no parameter packs available to expand
1>Main.cpp(36): error C3203: 'TypeList': unspecialized class template can't be used as a template argument for template parameter '_Ty2', expected a real type
1>Main.cpp(37): error C3203: 'TypeList': unspecialized class template can't be used as a template argument for template parameter '_Ty2', expected a real type
1>Main.cpp(40): error C2338: list1 != list3
1>Main.cpp(41): error C2338: list2 != list3
在可变参数解决后,为Wrapper添加所述A,B特化。
第二次编辑 - 找到了解决方法
所以,原始问题仍然存在,但经过一些试验和错误,我试图用单独的struct替换依赖类型,这似乎解决了这个问题:
template<typename scriptType>
struct getScript_impl
{
using type = ReqBuilder<typename scriptType::type>;
};
template<typename scriptType>
using getScript = typename getScript_impl<scriptType>::type;
/* REPLACING THIS WITH CODE ABOVE
template<typename scriptType>
using getScript = ReqBuilder<typename scriptType::type>;
*/
完整代码,适用于我的VS2015:http://ideone.com/kGT4qM
正如我在评论中简要说明的那样,我认为问题是使用依赖类型作为另一个模板参数的别名模板不会实例化该模板或类似的东西。(我不是模板向导,我真的只是戳他们,看看他们如何回应)。