我试图为值列表中的值建立索引的元查找器。
这是代码:
#include<type_traits>
#include<utility>
template <auto... Values>
struct ValueTplList;
template <auto>
constexpr int MetaFindV(int ind)
{ // not found case
return -1;
}
template <auto NeedleV, auto V, auto... Vs>
constexpr int MetaFindV(int ind = 0)
{
if constexpr (std::is_same_v<decltype(NeedleV), decltype(V)>)
{
return NeedleV == V ? ind : MetaFindV<NeedleV, Vs...>(ind + 1);
}
else
{
return MetaFindV<NeedleV, Vs...>(ind + 1);
}
}
// main
template <auto, typename>
struct MetaIndexOfV;
// destructurer
template <auto V, template<auto...> class Tmpl, auto... Vs>
struct MetaIndexOfV<V, Tmpl<Vs...> >
: std::integral_constant< int, MetaFindV<V, Vs...>() >
{};
// template variable version of it:
template <auto V, typename TemplInst>
constexpr int metaFindV_v = MetaIndexOfV<V, TemplInst>::value;
// tests
static_assert(metaFindV_v< 0, ValueTplList<0> > == 0 );
static_assert(metaFindV_v< 5, ValueTplList<0> > == -1);
static_assert(metaFindV_v< 0, ValueTplList<nullptr, 0> > == 1);
static_assert(metaFindV_v< 2, ValueTplList<1, (long)2, 2, 3, 4> > == 2);
static_assert(metaFindV_v< -1, ValueTplList<-2, -1, 42> > == 1);
在此处查找行为:
https://godbolt.org/z/ukwxpN
您会发现在gcc 7
及更高版本以及clang 5
及更高版本中都可以正常编译。
我想知道我是否真的按照MSVC强制执行的标准做错了什么。我现在无法自己看到它:'(
它说:
(30):错误C2672:'MetaFindV':找不到匹配的重载函数>(31):注意:请参见对正在编译的类模板实例化'MetaIndexOfV>'的引用
(30):错误C2975:'V':'MetaFindV'的无效模板参数,预期的编译时常量表达式 (12):注意:请参见“ V”的声明
(30):错误C2977:“ MetaFindV”:模板参数过多
我认为这是在抱怨
: std::integral_constant< int, MetaFindV<V, Vs...>() >
就像MetaFindV<V, Vs...>()
没有匹配功能一样。
(尾注:如果将auto
的所有typename
更改为-稍作调整-整个过程将开始工作(但当然仅适用于类型和类型列表),甚至尽管代码模式完全相同。)
答案 0 :(得分:1)
不是答案(对不起:我怀疑是MSVC错误,但不确定),但评论很长。
我提出了一种完全不同的方式来获取您想要的东西:
#include <type_traits>
#include <string>
template <auto... Values>
struct ValueTplList
{ };
template <auto, auto>
struct strongSame : public std::false_type
{ };
template <auto A>
struct strongSame<A, A> : public std::true_type
{ };
template <auto TargetVal, auto ... Values>
constexpr int foo (ValueTplList<Values...> const &)
{
int ind = -1;
(void)( (++ind, strongSame<TargetVal, Values>::value)
|| ... || (++ind, true) );
return std::size_t(ind) == sizeof...(Values) ? -1 : ind;
}
template <auto V, typename TemplInst>
constexpr int metaFindV_v = foo<V>(TemplInst{});
// tests
static_assert(metaFindV_v< 0, ValueTplList<0> > == 0 );
static_assert(metaFindV_v< 5, ValueTplList<0> > == -1);
static_assert(metaFindV_v< 0, ValueTplList<nullptr, 0> > == 1);
static_assert(metaFindV_v< 2, ValueTplList<1, (long)2, 2, 3, 4> > == 2);
static_assert(metaFindV_v< -1, ValueTplList<-2, -1, 42> > == 1);
int main ()
{
}
答案 1 :(得分:0)
我努力尝试并失败了。看来这是MSVC中的一个普通错误。
我对感兴趣的人的解决方案是完全放弃:'((( 相反,我使用了类型和值包装器,如下所示:
#include<type_traits>
#include<utility>
#include<variant>
template <typename... Types>
struct TypeList;
// auto: http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0127r1.html
template <auto... Values>
struct ValueTplList;
// meta technique to find index of a type in a typelist
template <typename>
constexpr int MetaFind(int ind)
{ // not found case
return -1;
}
template <typename NeedleT, typename T, typename... Ts>
constexpr int MetaFind(int ind = 0)
{
if (std::is_same_v<NeedleT, T>)
{
return ind;
}
else
{
return MetaFind<NeedleT, Ts...>(ind + 1);
}
}
// flat 2 template parameters versions
template <typename T, typename T2>
struct MetaIndexOf : std::integral_constant<int, -1>
{};
template <typename T>
struct MetaIndexOf<T,T> : std::integral_constant<int, 0>
{};
// destructurer version (access the contents of a typelist)
template <typename T, template<typename...> class Tmpl, typename... Ts>
struct MetaIndexOf<T, Tmpl<Ts...> >
: std::integral_constant< int, MetaFind<T, Ts...>() >
{};
// template variable version of it:
template <typename T, typename TemplInst>
constexpr int metaFind_v = MetaIndexOf<T, TemplInst>::value;
// test
static_assert(metaFind_v< bool, bool > == 0 );
static_assert(metaFind_v< bool, int > == -1 );
static_assert(metaFind_v< int, TypeList<bool, float, int, double> > == 2);
static_assert(metaFind_v< double, TypeList<bool, float, int, double> > == 3);
static_assert(metaFind_v< bool, TypeList<bool, float, int, double> > == 0);
static_assert(metaFind_v< long, TypeList<bool, float, int, double> > == -1);
// make a metaFind for values:
// let's try with a value wrapped in a type
template <auto V>
struct AnyConstantV : std::integral_constant<decltype(V), V>
{};
template <typename>
struct BoxAll;
// convenience helper to directly make a typelist of boxed values from values
template< template<auto...> class VL, auto... Vs >
struct BoxAll< VL<Vs...> >
{
using type = TypeList< AnyConstantV<Vs>... >;
};
static_assert( std::is_same_v< BoxAll<ValueTplList<0>>::type, TypeList<AnyConstantV<0>> > );
template <auto V, typename VL>
constexpr int metaFindV_v = metaFind_v< AnyConstantV<V>, typename BoxAll<VL>::type >;
// tests
static_assert(metaFindV_v< 0, ValueTplList<0> > == 0 );
static_assert(metaFindV_v< 5, ValueTplList<0> > == -1);
static_assert(metaFindV_v< 0, ValueTplList<nullptr, 0> > == 1);
// god dammnit visual studio ! ..... :(
static_assert(metaFindV_v< 2, ValueTplList<1, (long)2, 2, 3, 4> > == 2);
static_assert(metaFindV_v< -1, ValueTplList<-2, -1, 42> > == 1);
您可以在以下位置使用它:
https://godbolt.org/z/bnfZ5r
请注意,带有2的static_assert
不幸失败。再次,c在这里通过。最有趣的是,我不向你大喊大叫,intellisense正确无误:
(MSVC在此处应该没有断言的情况下进行构建)