我可以在模板参数扣除期间获得转换吗?

Can I get a conversion during template argument deduction?

本文关键字:转换 参数 我可以      更新时间:2023-10-16

我这里有这段代码:

#pragma once
using uInt = size_t;
template<uInt id> class idType {};
template<typename T> class typeId {};
#define Generate_Type_To_ID_Mapping(id, t)                          
class t;                                                            
template<>class idType<id> { public: using type = t; };             
template<>class typeId<t> { public: operator uInt() { return val; } 
typeId() = default;                                             
typeId(typeId const&) = delete;                                 
typeId& operator=(typeId const&) = delete;                      
typeId(typeId&&) = delete;                                      
typeId& operator=(typeId&&) = delete;                           
static constexpr uInt val = id;                                 
};
Generate_Type_To_ID_Mapping(0, Entity);
Generate_Type_To_ID_Mapping(1, RectComponent);
Generate_Type_To_ID_Mapping(2, ConstraintComponent);
Generate_Type_To_ID_Mapping(3, TextComponent);

这是一个宏,它为每个给定的<size_t, T>集制造 2 个模板专用化,一个模板从类型到索引的转换,另一个模板从索引到类型的转换。 它们被称为:

// type to index:
typeId<RectComponent>()  // the conversion operator returns 
// the value mapped to this type
// index to type:
idType<2>::type          // type is an alias to the mapped type

它们本身工作正常,但是如果我尝试将一个放在另一个内部idType<typeId<RectComponent>()>::type则代码将无法编译,我怀疑这是因为模板参数推断没有尝试任何转换(typeId<>()依赖于operator uInt()(

我有办法让它operator uInt()在模板参数推断期间被视为一种选择?

任何可以被视为函数声明的东西,编译器都会解析为函数声明。这被称为最令人烦恼的解析。typeId<RectComponent>()可以被视为函数声明:返回typeId<RectComponent>并接受参数的无名称函数。

这就是为什么你在idType<typeId<RectComponent>()>::type中得到一个错误:编译器尝试使用函数类型作为模板参数实例化idType模板。

等效代码为:

using T = typeId<RectComponent>();    // this line is OK, T is a function type
using Type = idType<T>::type;         // error is here

由于完全相同的原因,此等效代码无法编译

using Type = idType<typeId<RectComponent>()>::type;

不编译。


你想要什么:

constexpr uInt id = typeId<RectComponent>();
using Type = idType<id>::type;

您可以添加额外的括号以避免歧义:

using Type = idType<(typeId<RectComponent>())>::type;

这是有效的,因为(typeId<RectComponent>())不是有效的函数声明。

当然operator uInt()应该标constexpr

constexpr operator uInt() { return val; }

请参阅演示。

对于其他尝试这样做的人来说,值得一提的是,这个问题可以像这样完全避免:

template<typename T> class typeId_base {};
template<uInt id> class idType_base {};
template<uInt id>
using idType = typename idType_base<id>::type;
template<typename T>
inline constexpr uInt typeId = typeId_base<T>::val;
#define Generate_Type_To_ID_Mapping( id, t) 
class t;
template<>class typeId_base<t> { public: static constexpr uInt val = id;};
template<>class idType_base<id> { public: using type = t; };
Generate_Type_To_ID_Mapping(0, Entity);
Generate_Type_To_ID_Mapping(1, RectComponent);
Generate_Type_To_ID_Mapping(2, ConstraintComponent);
Generate_Type_To_ID_Mapping(3, TextComponent);

这允许简单地编写更简单和统一的idType<1>typeId<RectComponent>

int main()
{
//from type to index
std::cout << typeid(TextComponent).name() << " has ID " << typeId<TextComponent> << std::endl;
//from index to type
std::cout << typeid(idType<1>).name() << " has ID " << typeId<RectComponent> << std::endl;
}

甚至typeId<idType<1>>