Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 无法解释模棱两可的模板专门化_C++_Templates_C++11_Variadic - Fatal编程技术网

C++ 无法解释模棱两可的模板专门化

C++ 无法解释模棱两可的模板专门化,c++,templates,c++11,variadic,C++,Templates,C++11,Variadic,给定 出于某种原因,p的存在会导致歧义,因为当我将其替换为一个命名类型时,歧义就会消除。即使我用std::index_序列替换std::index_序列,歧义仍然存在。发生什么事?如何解决这个问题?下面是代码,它几乎与TupleTree的代码相同: TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber, P<Ts...>, First, Rest...> TupleTreeWi

给定

出于某种原因,
p
的存在会导致歧义,因为当我将其替换为一个命名类型时,歧义就会消除。即使我用
std::index_序列
替换
std::index_序列
,歧义仍然存在。发生什么事?如何解决这个问题?下面是代码,它几乎与TupleTree的代码相同:

TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber, P<Ts...>, First, Rest...>
TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, I, P<Ts...>, First, Rest...>
#包括
#包括
#包括
模板结构标识{using type=T;};
//合并类型包。
模板结构合并包;
模板
结构合并包:标识{};
模板
结构MergePacks:MergePacks{};
//将类型追加到包中。
模板结构类型;
模板
结构追加类型{
使用类型=P;
};
//ExpandPackWithTuple获取一个包,并创建N个包,每个包以元组的元素结尾,N是元组的大小。
模板结构ExpandPackWithTupleHelper;
模板
结构ExpandPackWithTupleHelper{
使用类型=P;
};
模板
使用ExpandPackWithTuple=typename ExpandPackWithTupleHelper::type;
//TupleTreeWithRepeats。
模板结构TupleTreeWithRepeatsHelper;
模板
结构TupleTreeWithRepeatsHelper:
TupleTreeWithRepeatsHelper{};
模板
结构TupleTreeWithRepeatsHelper:
TupleTreeWithRepeatsHelper{};
模板
结构TupleTreeWithRepeatsHelper{
使用类型=输出包;
};
模板结构TupleTreeWithRepeats;
模板
结构TupleTreeWithRepeats:TupleTreeWithRepeatsHelper{};
//测试
模板结构包;
使用T1=std::tuple;
使用T2=std::tuple;
使用T3=std::tuple;
int main(){
标准::cout

>::value据我所知,这两个词不应该模棱两可

不管怎样,一个简单的解决方法是只实施“有重复”而不是“无重复”:

有人可能会说,这也是一个更好的设计


最小化为:

template<class T, std::size_t> using id = T;

template<class T, std::size_t... Is>
Pack<id<T, Is>...> do_repeat(std::index_sequence<Is...>);

template<class T, std::size_t I>
using repeat = decltype(do_repeat<T>(std::make_index_sequence<I>()));
模板类Purr{};
模板
结构喵喵;
模板
结构Meow{};
模板
结构Meow{};
喵喵叫c;

GCC报告了一个模棱两可的问题,这在我看来肯定是一个错误。Clang正确地处理了这个问题。

虽然T.C.的解决方法肯定更优雅,但我发现这个解决方法可能是在遇到GCC错误时应该始终有效的一般解决方法。我没有避免GCC错误,而是直接面对它。只需替换
P
使用单个类型名,并定义使用该类型名的单独元函数:

template<class> class Purr { };

template <template <class> class, class>
struct Meow;

template <template <class> class P>
struct Meow<P, P<int>> { };

template <template <class> class P, class T>
struct Meow<P, P<T>> { };

Meow<Purr, Purr<int>> c;
模板结构AddToOutput;
模板
结构AddToOutput:MergePacks{};
//我的解决方法是使用struct AddToOutput。
模板
结构TupleTreeWithRepeatsHelper:
TupleTreeWithRepeatsHelper{};
模板
结构TupleTreeWithRepeatsHelper:
TupleTreeWithRepeatsHelper{};
整个代码:

template <template <typename...> class P, typename OutputPack, typename Tuple> struct AddToOutput;

template <template <typename...> class P, typename... Ts, typename Tuple>
struct AddToOutput<P, P<Ts...>, Tuple> : MergePacks<ExpandPackWithTuple<P, Ts, Tuple>...> {};

// My workaround, using struct AddToOutput.
template <template <typename...> class P, std::size_t... Is, std::size_t LoopNumber, typename OutputPack, typename First, typename... Rest>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber, OutputPack, First, Rest...> :
    TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber + 1, typename AddToOutput<P, OutputPack, First>::type, First, Rest...> {};

template <template <typename...> class P, std::size_t I, std::size_t... Is, typename OutputPack, typename First, typename... Rest>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, I, OutputPack, First, Rest...> :
    TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, 1, typename AddToOutput<P, OutputPack, First>::type, Rest...> {};
#包括
#包括
模板结构标识{using type=T;};
//合并类型包。
模板结构合并包;
模板
结构合并包:标识{};
模板
结构MergePacks:MergePacks{};
//将类型追加到包中。
模板结构类型;
模板
结构追加类型{
使用类型=P;
};
//ExpandPackWithTuple获取一个包,并创建N个包,每个包以该元组的元素结尾,其中N是元组的大小。
模板结构ExpandPackWithTupleHelper;
模板
结构ExpandPackWithTupleHelper{
使用类型=P;
};
模板
使用ExpandPackWithTuple=typename ExpandPackWithTupleHelper::type;
//现在,对于TupleTree本身。
模板结构TupleTreeHelper;
模板
结构TupleTreeHelper:TupleTreeHelper{};
模板
结构TupleTreeHelper{
使用类型=输出包;
};
模板
使用TupleTree=typename TupleTreeHelper::type;
//TupleTreeWithRepeats。
模板结构TupleTreeWithRepeatsHelper;
template struct AddToOutput;//这仅用于解决下面解释的GCC 5.1错误。
模板
结构AddToOutput:MergePacks{};
//以下两个专门化在GCC5.1中遇到了歧义,尽管Clang运行得很好,但被窃听的是GCC。
//模板
//结构TupleTreeWithRepeatsHelper:
//TupleTreeWithRepeatsHelper{};
//
//模板
//结构TupleTreeWithRepeatsHelper:
//TupleTreeWithRepeatsHelper{};
//我的解决方法是使用struct AddToOutput。
模板
结构TupleTreeWithRepeatsHelper:
TupleTreeWithRepeatsHelper{};
模板
结构TupleTreeWithRepeatsHelper:
TupleTreeWithRepeatsHelper{};
模板
结构TupleTreeWithRepeatsHelper{
使用类型=输出包;
};
模板结构TupleTreeWithRepeats;
模板
结构TupleTreeWithRepeats:TupleTreeWithRepeatsHelper{};
//测试
#包括
模板结构包;
使用T1=std::tuple;
使用T2=std::tuple;
使用T3=std::tuple;
int main(){

std::cout有趣的是,对于clang来说,它并不含糊:我正在使用GCC 5.1进行编译。顺便说一句,我刚刚稍微编辑了我的代码,因为我在第二个专门化中发现了一个逻辑错误。但含糊性仍然是主要问题。但在我微调专门化和测试输出之前,需要首先消除含糊性。@MarcoA我认为编译只是在那个时间上进行的。看看输出的深度越低,看起来CLAN就开始进行一些无限递归。@ TC。我倾向于认为你是对的,尽管我希望得到一个反馈,谢谢T.C.的解决方法,但是因为理解C++语言比M更重要。y程序,第一个实现是否真的模棱两可?我知道你陈述了你的观点。但是如果它真的模棱两可,像你上面的解决方案这样的解决方案会永远存在吗?
#include <iostream>
#include <tuple>
#include <type_traits>

template <typename T> struct Identity { using type = T; };

// Merging packs of types.
template <typename...> struct MergePacks;

template <typename Pack>
struct MergePacks<Pack> : Identity<Pack> {};

template <template <typename...> class P, typename... Types1, typename... Types2, typename... Packs>
struct MergePacks<P<Types1...>, P<Types2...>, Packs...> : MergePacks<P<Types1..., Types2...>, Packs...> {};

// Appending a type to a pack.
template <typename Pack, typename T> struct AppendType;

template <template <typename...> class P, typename... Ts, typename T>
struct AppendType <P<Ts...>, T> {
    using type = P<Ts..., T>;
};

// ExpandPackWithTuple takes a pack, and creates N packs that each end with the tuple's elements, N is the size of the tuple.
template <template <typename...> class P, typename Pack, typename Tuple, typename Indices> struct ExpandPackWithTupleHelper;

template <template <typename...> class P, typename Pack, typename Tuple, std::size_t... Is>
struct ExpandPackWithTupleHelper<P, Pack, Tuple, std::index_sequence<Is...>> {
    using type = P<typename AppendType<Pack, typename std::tuple_element<Is, Tuple>::type>::type...>;
};

template <template <typename...> class P, typename Pack, typename Tuple>
using ExpandPackWithTuple = typename ExpandPackWithTupleHelper<P, Pack, Tuple, std::make_index_sequence<std::tuple_size<Tuple>::value>>::type;

// TupleTreeWithRepeats.
template <template <typename...> class P, typename NumRepeats, std::size_t LoopNumber, typename OutputPack, typename... Tuples> struct TupleTreeWithRepeatsHelper;

template <template <typename...> class P, std::size_t I, std::size_t... Is, std::size_t LoopNumber, typename... Ts, typename First, typename... Rest>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, LoopNumber, P<Ts...>, First, Rest...> :
    TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, LoopNumber + 1, typename MergePacks<ExpandPackWithTuple<P, Ts, First>...>::type, First, Rest...> {};

template <template <typename...> class P, std::size_t I, std::size_t... Is, typename... Ts, typename First, typename... Rest>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, I, P<Ts...>, First, Rest...> :
    TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, 0, typename MergePacks<ExpandPackWithTuple<P, Ts, First>...>::type, Rest...> {};

template <template <typename...> class P, std::size_t... Is, std::size_t LoopNumber, typename OutputPack>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber, OutputPack> {
    using type = OutputPack;
};

template <template <typename...> class P, typename NumRepeats, typename... Tuples> struct TupleTreeWithRepeats;

template <template <typename...> class P, std::size_t I, std::size_t... Is, typename... Tuples>
struct TupleTreeWithRepeats<P, std::index_sequence<I, Is...>, Tuples...> : TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, 0, P<P<>>, Tuples...> {};

// Testing
template <typename...> struct Pack;
using T1 = std::tuple<int, char, double>;
using T2 = std::tuple<bool, double, int, char>;
using T3 = std::tuple<double, int>;

int main() {
    std::cout << std::is_same<
        TupleTreeWithRepeats<Pack, std::index_sequence<1,1,1>, T1, T2, T3>::type,
        Pack<
            Pack<int, bool, double>, Pack<int, bool, int>, Pack<int, double, double>, Pack<int, double, int>, Pack<int, int, double>, Pack<int, int, int>, Pack<int, char, double>, Pack<int, char, int>,
            Pack<char, bool, double>, Pack<char, bool, int>, Pack<char, double, double>, Pack<char, double, int>, Pack<char, int, double>, Pack<char, int, int>, Pack<char, char, double>, Pack<char, char, int>,
            Pack<double, bool, double>, Pack<double, bool, int>, Pack<double, double, double>, Pack<double, double, int>, Pack<double, int, double>, Pack<double, int, int>, Pack<double, char, double>, Pack<double, char, int>
        >
    >::value << '\n';  // ambiguous
}
// TupleTreeWithRepeats.
template <template <typename...> class P, typename Tuples>
struct TupleTreeWithRepeatsHelper;

template <template <typename...> class P, typename... Tuples>
struct TupleTreeWithRepeatsHelper<P, Pack<Tuples...>> :
    Identity<TupleTree<P, Tuples...>> {};

template <template <typename...> class P, typename NumRepeats, typename... Tuples> 
struct TupleTreeWithRepeats;

template <template <typename...> class P, std::size_t... Is, typename... Tuples>
struct TupleTreeWithRepeats<P, std::index_sequence<Is...>, Tuples...> :
    TupleTreeWithRepeatsHelper<P, typename MergePacks<repeat<Tuples, Is>...>::type> {};
template<class T, std::size_t> using id = T;

template<class T, std::size_t... Is>
Pack<id<T, Is>...> do_repeat(std::index_sequence<Is...>);

template<class T, std::size_t I>
using repeat = decltype(do_repeat<T>(std::make_index_sequence<I>()));
template<class> class Purr { };

template <template <class> class, class>
struct Meow;

template <template <class> class P>
struct Meow<P, P<int>> { };

template <template <class> class P, class T>
struct Meow<P, P<T>> { };

Meow<Purr, Purr<int>> c;
template <template <typename...> class P, typename OutputPack, typename Tuple> struct AddToOutput;

template <template <typename...> class P, typename... Ts, typename Tuple>
struct AddToOutput<P, P<Ts...>, Tuple> : MergePacks<ExpandPackWithTuple<P, Ts, Tuple>...> {};

// My workaround, using struct AddToOutput.
template <template <typename...> class P, std::size_t... Is, std::size_t LoopNumber, typename OutputPack, typename First, typename... Rest>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber, OutputPack, First, Rest...> :
    TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber + 1, typename AddToOutput<P, OutputPack, First>::type, First, Rest...> {};

template <template <typename...> class P, std::size_t I, std::size_t... Is, typename OutputPack, typename First, typename... Rest>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, I, OutputPack, First, Rest...> :
    TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, 1, typename AddToOutput<P, OutputPack, First>::type, Rest...> {};
#include <iostream>
#include <tuple>

template <typename T> struct Identity { using type = T; };

// Merging packs of types.
template <typename...> struct MergePacks;

template <typename Pack>
struct MergePacks<Pack> : Identity<Pack> {};

template <template <typename...> class P, typename... Types1, typename... Types2, typename... Packs>
struct MergePacks<P<Types1...>, P<Types2...>, Packs...> : MergePacks<P<Types1..., Types2...>, Packs...> {};

// Appending a type to a pack.
template <typename Pack, typename T> struct AppendType;

template <template <typename...> class P, typename... Ts, typename T>
struct AppendType <P<Ts...>, T> {
    using type = P<Ts..., T>;
};

// ExpandPackWithTuple takes a pack, and creates N packs that each end with the tuple's elements, where N is the size of the tuple.
template <template <typename...> class P, typename Pack, typename Tuple, typename Indices> struct ExpandPackWithTupleHelper;

template <template <typename...> class P, typename Pack, typename Tuple, std::size_t... Is>
struct ExpandPackWithTupleHelper<P, Pack, Tuple, std::index_sequence<Is...>> {
    using type = P<typename AppendType<Pack, typename std::tuple_element<Is, Tuple>::type>::type...>;
};

template <template <typename...> class P, typename Pack, typename Tuple>
using ExpandPackWithTuple = typename ExpandPackWithTupleHelper<P, Pack, Tuple, std::make_index_sequence<std::tuple_size<Tuple>::value>>::type;

// Now, for TupleTree itself.
template <template <typename...> class P, typename OutputPack, typename... Tuples> struct TupleTreeHelper;

template <template <typename...> class P, typename... Ts, typename First, typename... Rest>
struct TupleTreeHelper<P, P<Ts...>, First, Rest...> : TupleTreeHelper<P, typename MergePacks<ExpandPackWithTuple<P, Ts, First>...>::type, Rest...> {};

template <template <typename...> class P, typename OutputPack>
struct TupleTreeHelper<P, OutputPack> {
    using type = OutputPack;
};

template <template <typename...> class P, typename... Tuples>
using TupleTree = typename TupleTreeHelper<P, P<P<>>, Tuples...>::type;

// TupleTreeWithRepeats.
template <template <typename...> class P, typename NumRepeats, std::size_t LoopNumber, typename OutputPack, typename... Tuples> struct TupleTreeWithRepeatsHelper;

template <template <typename...> class P, typename OutputPack, typename Tuple> struct AddToOutput;  // This is only needed for a workaround against the GCC 5.1 bug explained below.

template <template <typename...> class P, typename... Ts, typename Tuple>
struct AddToOutput<P, P<Ts...>, Tuple> : MergePacks<ExpandPackWithTuple<P, Ts, Tuple>...> {};

// The following two specializations run into ambiguity with GCC 5.1, though Clang runs it fine.  It is GCC that is bugged.
//template <template <typename...> class P, std::size_t... Is, std::size_t LoopNumber, typename... Ts, typename First, typename... Rest>
//struct TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber, P<Ts...>, First, Rest...> :
//  TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber + 1, typename MergePacks<ExpandPackWithTuple<P, Ts, First>...>::type, First, Rest...> {};
//
//template <template <typename...> class P, std::size_t I, std::size_t... Is, typename... Ts, typename First, typename... Rest>
//struct TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, I, P<Ts...>, First, Rest...> :
//  TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, 1, typename MergePacks<ExpandPackWithTuple<P, Ts, First>...>::type, Rest...> {};

// My workaround, using struct AddToOutput.
template <template <typename...> class P, std::size_t... Is, std::size_t LoopNumber, typename OutputPack, typename First, typename... Rest>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber, OutputPack, First, Rest...> :
    TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, LoopNumber + 1, typename AddToOutput<P, OutputPack, First>::type, First, Rest...> {};

template <template <typename...> class P, std::size_t I, std::size_t... Is, typename OutputPack, typename First, typename... Rest>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<I, Is...>, I, OutputPack, First, Rest...> :
    TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, 1, typename AddToOutput<P, OutputPack, First>::type, Rest...> {};

template <template <typename...> class P, typename OutputPack>
struct TupleTreeWithRepeatsHelper<P, std::index_sequence<>, 1, OutputPack> {
    using type = OutputPack;
};

template <template <typename...> class P, typename NumRepeats, typename... Tuples> struct TupleTreeWithRepeats;

template <template <typename...> class P, std::size_t... Is, typename... Tuples>
struct TupleTreeWithRepeats<P, std::index_sequence<Is...>, Tuples...> : TupleTreeWithRepeatsHelper<P, std::index_sequence<Is...>, 1, P<P<>>, Tuples...> {};

// Testing
#include <type_traits>

template <typename...> struct Pack;
using T1 = std::tuple<int, char, double>;
using T2 = std::tuple<bool, double, int, char>;
using T3 = std::tuple<double, int>;

int main() {
    std::cout << std::boolalpha;
    std::cout << std::is_same<
        ExpandPackWithTuple<Pack, Pack<int, bool>, std::tuple<int, char, double>>,
        Pack<Pack<int, bool, int>, Pack<int, bool, char>, Pack<int, bool, double>>
    >::value << '\n';  // true

    std::cout << std::is_same<
        MergePacks<ExpandPackWithTuple<Pack, Pack<>, T1>>::type,
        Pack<Pack<int>, Pack<char>, Pack<double>>
    >::value << '\n';  // true

    std::cout << std::is_same<
        MergePacks<ExpandPackWithTuple<Pack, Pack<int>, T2>, ExpandPackWithTuple<Pack, Pack<char>, T2>, ExpandPackWithTuple<Pack, Pack<double>, T2>>::type,
        Pack<
            Pack<int, bool>, Pack<int, double>, Pack<int, int>, Pack<int, char>,
            Pack<char, bool>, Pack<char, double>, Pack<char, int>, Pack<char, char>,
            Pack<double, bool>, Pack<double, double>, Pack<double, int>, Pack<double, char>
        >
    >::value << '\n';  // true

    std::cout << std::is_same<
        TupleTree<Pack, T1, T2>,
        Pack<
            Pack<int, bool>, Pack<int, double>, Pack<int, int>, Pack<int, char>,
            Pack<char, bool>, Pack<char, double>, Pack<char, int>, Pack<char, char>,
            Pack<double, bool>, Pack<double, double>, Pack<double, int>, Pack<double, char>
        >
    >::value << '\n';  // true

    std::cout << std::is_same<
        TupleTree<Pack, T1, T2, T3>,
        Pack<
            Pack<int, bool, double>, Pack<int, bool, int>, Pack<int, double, double>, Pack<int, double, int>, Pack<int, int, double>, Pack<int, int, int>, Pack<int, char, double>, Pack<int, char, int>,
            Pack<char, bool, double>, Pack<char, bool, int>, Pack<char, double, double>, Pack<char, double, int>, Pack<char, int, double>, Pack<char, int, int>, Pack<char, char, double>, Pack<char, char, int>,
            Pack<double, bool, double>, Pack<double, bool, int>, Pack<double, double, double>, Pack<double, double, int>, Pack<double, int, double>, Pack<double, int, int>, Pack<double, char, double>, Pack<double, char, int>
        >
    >::value << '\n';  // true

    std::cout << std::is_same<
        TupleTreeWithRepeats<Pack, std::index_sequence<1,1>, T1, T2>::type,
        Pack<
            Pack<int, bool>, Pack<int, double>, Pack<int, int>, Pack<int, char>,
            Pack<char, bool>, Pack<char, double>, Pack<char, int>, Pack<char, char>,
            Pack<double, bool>, Pack<double, double>, Pack<double, int>, Pack<double, char>
        >
    >::value << '\n';  // true

    std::cout << std::is_same<
        TupleTreeWithRepeats<Pack, std::index_sequence<1,1,1>, T1, T2, T3>::type,
        Pack<
            Pack<int, bool, double>, Pack<int, bool, int>, Pack<int, double, double>, Pack<int, double, int>, Pack<int, int, double>, Pack<int, int, int>, Pack<int, char, double>, Pack<int, char, int>,
            Pack<char, bool, double>, Pack<char, bool, int>, Pack<char, double, double>, Pack<char, double, int>, Pack<char, int, double>, Pack<char, int, int>, Pack<char, char, double>, Pack<char, char, int>,
            Pack<double, bool, double>, Pack<double, bool, int>, Pack<double, double, double>, Pack<double, double, int>, Pack<double, int, double>, Pack<double, int, int>, Pack<double, char, double>, Pack<double, char, int>
        >
    >::value << '\n';  // true
}