C++ 未能正确推断GCC中可变类型和非类型模板参数包的混合
好了,伙计们,我尝试最小化以下代码来说明我遇到的问题。它看起来相当糟糕,并且省略了许多原始代码。虽然不一定与我遇到的问题相关,但我正在尝试实现一种依赖注入机制。我试图设计它,使从已经依赖注入的类派生的类能够从各自的父类继承依赖关系。如果需要,我可以提供完整的代码,但是这个更简单的版本足以产生问题C++ 未能正确推断GCC中可变类型和非类型模板参数包的混合,c++,c++11,gcc,c++14,variadic-templates,C++,C++11,Gcc,C++14,Variadic Templates,好了,伙计们,我尝试最小化以下代码来说明我遇到的问题。它看起来相当糟糕,并且省略了许多原始代码。虽然不一定与我遇到的问题相关,但我正在尝试实现一种依赖注入机制。我试图设计它,使从已经依赖注入的类派生的类能够从各自的父类继承依赖关系。如果需要,我可以提供完整的代码,但是这个更简单的版本足以产生问题 #include <tuple> #include <type_traits> template<typename ... Dependencies> class
#include <tuple>
#include <type_traits>
template<typename ... Dependencies>
class DependencyInjectable
{
public:
typedef DependencyInjectable<Dependencies ...> tDependencies;
typedef tDependencies tDependencyInjectable;
typedef std::tuple<Dependencies ...> tTuple;
static const constexpr size_t Depth = 0;
template<typename Arg, typename DecayArg = typename std::decay<Arg>::type, typename ... Args,
typename = std::enable_if_t<!std::is_same<DecayArg, bool>::value>>
DependencyInjectable(Arg &&arg, Args && ... args) { }
virtual ~DependencyInjectable(void) { }
};
template<typename T> struct tuple_as_dependency_injectable_type { };
template<typename ... Args> struct tuple_as_dependency_injectable_type<std::tuple<Args ...>>
{
typedef DependencyInjectable<Args ...> type;
};
template<typename T> struct dependencies_of { typedef T type; };
template<typename Dependency, typename ... Dependencies>
class DependencyInjectable<dependencies_of<Dependency>, Dependencies ...>
: virtual public Dependency::tDependencyInjectable,
public tuple_as_dependency_injectable_type<decltype(std::tuple_cat(std::declval<
typename Dependency::tDependencyInjectable::tTuple>(),
std::declval<std::tuple<Dependencies ...>>()))>::type
{
public:
template<typename Arg, bool = Arg::Depth != 0, typename ... Args>
struct get_virtual_bases
{
typedef typename Arg::tBase T;
typedef typename get_virtual_bases<T, T::Depth != 0,
typename Arg::tDependencyInjectable, Args ...>::type type;
};
template<typename Arg, typename ... Args>
struct get_virtual_bases<Arg, false, Args ...>
{
typedef std::tuple<typename Arg::tDependencyInjectable, Args ...> type;
};
typedef decltype(std::tuple_cat(std::declval<typename Dependency::tDependencyInjectable::tTuple>(),
std::declval<std::tuple<Dependencies ...>>())) tTuple;
typedef typename tuple_as_dependency_injectable_type<tTuple>::type tDependencies;
typedef DependencyInjectable<dependencies_of<Dependency>, Dependencies ...> tDependencyInjectable;
typedef Dependency tBase;
static const constexpr auto Depth = 1 + std::tuple_size<typename get_virtual_bases<tBase>::type>::value;
template<typename Arg, typename ... Args, typename std::enable_if<
!std::is_same<typename std::decay<Arg>::type, decltype(std::make_index_sequence<Depth - 1>{ })>::value, int>::type = 0>
DependencyInjectable(Arg &&arg, Args && ... args)
: DependencyInjectable(std::make_index_sequence<Depth - 1>{ }, std::make_index_sequence<1 + sizeof ... (Args)> { },
std::forward_as_tuple(arg, std::forward<Args>(args) ...)) { }
private:
template<typename ... Args, size_t ... IndicesOne, size_t ... IndicesTwo>
DependencyInjectable(const std::index_sequence<IndicesOne ...> &, const std::index_sequence<IndicesTwo ...> &,
const std::tuple<Args ...> &tuple)
: std::tuple_element<IndicesOne, typename get_virtual_bases<
typename Dependency::tDependencyInjectable>::type>::type(std::get<IndicesTwo>(tuple) ...) ...,
tDependencies(std::get<IndicesTwo>(tuple) ...) { }
public:
virtual ~DependencyInjectable(void) { }
};
#包括
#包括
模板
类依赖可注入
{
公众:
类型定义依赖性可注射tDependencies;
typedef tdependencys tDependencyInjectable;
typedef std::tuple tTuple;
静态常数constexpr size\u t Depth=0;
模板>
DependencyInjectable(Arg&&Arg,Args&&Args){}
虚~DependencyInjectable(void){}
};
模板结构元组作为依赖项可注入类型{};
模板结构元组作为依赖项可注入类型
{
typedef依赖注入型;
};
{typedef T type;}的模板结构依赖项;
模板
类依赖可注入
:虚拟公共依赖项::tDependencyInjectable,
公共元组作为依赖项可注入类型(),
std::declval())>::类型
{
公众:
模板
结构获取虚拟基
{
typedef typename Arg::tBase T;
typedef typename get_virtual_base::type type;
};
模板
结构获取虚拟基
{
typedef std::元组类型;
};
typedef decltype(std::tuple_cat(std::declval(),
std::declval()))t对;
typedef typename tuple_as_dependency_injectable_type::type tDependencies;
类型依赖性可注射tDependencyInjectable;
typedef依赖性tBase;
静态常量constexpr auto Depth=1+std::tuple\u size::value;
模板::类型=0>
DependencyInjectable(Arg&&Arg,Args&&Args)
:DependencyInjectable(std::make_index_sequence{},std::make_index_sequence{},
std::forward作为元组(arg,std::forward(args)…){
私人:
模板
DependencyInjectable(常数std::index_序列&,常数std::index_序列&,
常量std::元组和元组)
:std::tuple_元素::type>::type(std::get(tuple)。。。,
tDependencies(std::get(tuple)…{}
公众:
虚~DependencyInjectable(void){}
};
以下是测试该类的代码段:
struct DependencyOne { };
struct DependencyTwo { };
class DependentClassOne
: virtual public DependencyInjectable<DependencyOne *>
{
public:
DependentClassOne(const tDependencies &dependencies) : tDependencyInjectable(dependencies) { }
virtual ~DependentClassOne(void) { }
};
class DependentClassTwo
: public DependentClassOne,
virtual public DependencyInjectable<dependencies_of<DependentClassOne>, DependencyTwo *>
{
public:
DependentClassTwo(const tDependencies &dependencies)
: tBase(dependencies),
tBase::DependencyInjectable(dependencies),
tDependencyInjectable(dependencies) { }
virtual ~DependentClassTwo(void) { }
};
int main(int argc, char **argv)
{
DependencyOne dependencyOne;
DependencyTwo dependencyTwo;
auto &&tuple = std::make_tuple(&dependencyOne, &dependencyTwo);
DependentClassOne dependentClassOne(tuple);
DependentClassTwo dependentClassTwo(tuple);
return 0;
}
struct DependencyOne{};
结构依赖性二{};
类依赖项类
:虚拟公共依赖项可注入
{
公众:
DependentClassOne(const tDependencies&dependencies):tDependencyInjectable(dependencies){}
虚~DependentClassOne(void){}
};
类dependentClass2
:public DependentClassOne,
虚拟公共依赖项可注入
{
公众:
DependentClassThou(常量tDependencies&dependencies)
:t数据库(依赖项),
tBase::DependencyInjectable(依赖项),
tDependencyInjectable(依赖项){}
虚~DependentClassTwo(void){}
};
int main(int argc,字符**argv)
{
依赖一个依赖一个;
依赖二依赖二;
auto&&tuple=std::make_tuple(&dependencyOne和&dependencyTwo);
DependentClassOne DependentClassOne(元组);
DependentClassThound DependentClassThou(元组);
返回0;
}
使用GCC 6.3.0编译此代码会产生以下错误:
: In instantiation of 'DependencyInjectable<dependencies_of<Dependency>, Dependencies ...>::DependencyInjectable(std::index_sequence<IndicesOne ...>&, std::index_
sequence<IndicesTwo ...>&, const std::tuple<_Args1 ...>&) [with Args = {const DependencyInjectable<DependencyOne*, DependencyTwo*>&}; long long unsigned int ...IndicesOne = {0ull}; long long unsigned
int ...IndicesTwo = {0ull}; Dependency = DependentClassOne; Dependencies = {DependencyTwo*}; std::index_sequence<IndicesOne ...> = std::integer_sequence<long long unsigned int, 0ull>; std::index_seque
nce<IndicesTwo ...> = std::integer_sequence<long long unsigned int, 0ull>]':
:63:88: required from 'DependencyInjectable<dependencies_of<Dependency>, Dependencies ...>::DependencyInjectable(Arg&&, Args&& ...) [with Arg = const Dependency
Injectable<DependencyOne*, DependencyTwo*>&; Args = {}; typename std::enable_if<(! std::is_same<typename std::decay<Arg>::type, decltype (typename std::_Make_integer_sequence<long long unsigned int, (
DependencyInjectable<dependencies_of<Dependency>, Dependencies ...>::Depth - 1), typename std::_Build_index_tuple<(DependencyInjectable<dependencies_of<Dependency>, Dependencies ...>::Depth - 1)>::__t
ype>::__type{})>::value), int>::type <anonymous> = 0; Dependency = DependentClassOne; Dependencies = {DependencyTwo*}]'
:99:41: required from here
:72:54: error: no matching function for call to 'DependencyInjectable<DependencyOne*>::DependencyInjectable(bool)'
tDependencies(std::get<IndicesTwo>(tuple) ...) { }
^
:16:5: note: candidate: template<class Arg, class DecayArg, class ... Args, class> DependencyInjectable<Dependencies>::DependencyInjectable(Arg&&, Args&& ...)
DependencyInjectable(Arg &&arg, Args && ... args) { }
^~~~~~~~~~~~~~~~~~~~
:16:5: note: template argument deduction/substitution failed:
:5:7: note: candidate: constexpr DependencyInjectable<DependencyOne*>::DependencyInjectable(const DependencyInjectable<DependencyOne*>&)
class DependencyInjectable
^~~~~~~~~~~~~~~~~~~~
:5:7: note: no known conversion for argument 1 from 'bool' to 'const DependencyInjectable<DependencyOne*>&'
:在'DependencyInjectable::DependencyInjectable(std::index_sequence&,std::index'的实例化中_
序列&,常数std::tuple&[带Args={const DependencyInjectable&};long long unsigned int…指示符one={0ull};long long unsigned
int…IndicesTwo={0ull};Dependency=dependentclasson;Dependency={DependencyTwo*};std::index_sequence=std::integer_sequence;std::index_sequence
nce=std::整数_序列]':
:63:88:从'DependencyInjectable::DependencyInjectable(Arg&&,Args&&…[带Arg=const Dependency]中需要
可注入&;Args={};typename std::enable_if::type=0;Dependency=DependentClassOne;dependencitytwo*}
:99:41:从这里开始需要
:72:54:错误:调用“DependencyInjectable::DependencyInjectable(bool)”时没有匹配的函数
tDependencies(std::get(tuple)…{}
^
:16:5:注意:候选:模板DependencyInjectable::DependencyInjectable(Arg&&,Args&&…)
DependencyInjectable(Arg&&Arg,Args&&Args){}
^~~~~~~~~~~~~~~~~~~~
:16:5:注意:模板参数扣除/替换失败:
:5:7:注意:候选:constexpr DependencyInjectable::DependencyInjectable(const DependencyInjectable&)
类依赖可注入
^~~~~~~~~~~~~~~~~~~~
:5:7:注意:参数1从'bool'到'const DependencyInjectable&'的转换未知
具体而言,我对GCC为何会发出此错误感到困惑:
:72:54:错误:调用“DependencyInjectable::DependencyInjectable(bool)”时没有匹配的函数
tDependencies(std::get(tuple)…{}
显然,模板参数推断是失败的,但我不知道为什么。'bool'是如何推导出来的?GCC似乎在与以下路线抗争:
typename Dependency::tDependencyInjectable>::type>::type(std::get<IndicesTwo>(tuple) ...) ...,
typename依赖项::tDependencyInjectable>::type>::type(std::get(tuple)。。。,
我特意在基类中添加了以下构造函数来解决这个问题:
template<typename Arg, typename DecayArg = typename std::decay<Arg>::type, typename ... Args,
typename = std::enable_if_t<!std::is_same<DecayArg, bool>::value>>
DependencyInjectable(Arg &&arg, Args && ... args) { }
模板>
DependencyInjectable(Arg&&Arg,Args&&Args){}
此代码已被Microsoft Visual Studio 14接受并按预期运行。一个稍微不同的版本会编译成叮当声,尽管这个特定的版本可能不会。Clang和Visual Studio都是正确的,或者GCC正确地拒绝了我的代码。我错过了什么?每当我看到deduc