【问题标题】:Name (or refer) a specialized template parameter命名(或引用)一个专门的模板参数
【发布时间】:2020-04-28 12:56:58
【问题描述】:

我决定使用以下模式自动组合各种类型的对象及其配置:

enum class Type { Car, Person };

template< Type TYPE >
struct Object;

template< Type TYPE >
struct ObjectConfig;

template<>
struct ObjectConfig< Type::Car >
{
};

// Version 1
template<>
struct Object< Type::Car >: public ObjectConfig< Type::Car > // How could I avoid this duplication???
{
};

// Version 2
template<>
struct Object< Type::Car >
{
    static constexpr Type myType{ Type::Car }; // How could I avoid this duplication???
    ObjectConfig< myType > m_params;
};

它旨在防错和自动,但我无法避免两次写入枚举值(这很容易出错并且根本不是自动的)。 我想写一些类似的东西(所以我想以某种方式引用专门的参数):

template< Type TYPE >
struct Object;

template<>
struct Object< Type::Car >: public ObjectConfig< TYPE >
{
};

有什么技巧可以用来实现类似的目标吗?

提前谢谢你!

请查详细代码here (code)

【问题讨论】:

  • 这样的? template &lt;Type T=Type::Car&gt; struct Object : public ObjectConfig&lt; T &gt; { }; Object&lt;&gt; a;
  • 正如我所见,您建议的代码不是模板专业化,而是具有默认值的重新定义。当然会有很多特化(汽车、人等),所以默认值是不合适的。
  • 然后使用宏。

标签: c++ c++11 templates c++14


【解决方案1】:

虽然有点复杂,但我对这两个版本都有解决方案。

#include <type_traits>

enum class Type { Car, Person, Truck };

template<Type TYPE>
struct ObjectConfig;

template<>
struct ObjectConfig<Type::Car>
{ };

template<>
struct ObjectConfig<Type::Person>
{ };

template<Type T>
struct FakeDependency: public std::false_type
{ };

template<Type TYPE, Type DELEGATED_TYPE = TYPE, typename DUMMY = typename std::enable_if<DELEGATED_TYPE == TYPE>::type >
struct Object;

template<Type TYPE, Type DELEGATED_TYPE, typename DUMMY>
struct Object
{
    static_assert( FakeDependency<DELEGATED_TYPE>::value, "Not supported!" );
};

template<Type DELEGATED_TYPE, typename DUMMY>
struct Object<Type::Car, DELEGATED_TYPE, DUMMY>
{
    ObjectConfig<DELEGATED_TYPE> m_params;
};

template<Type DELEGATED_TYPE, typename DUMMY>
struct Object<Type::Person, DELEGATED_TYPE, DUMMY> : public ObjectConfig<DELEGATED_TYPE>
{ };

int main() {
    Object<Type::Car> c;
    Object<Type::Person> p;
    //Object<Type::Truck> t;  // Static assertion
    //Object<Type::Car, Type::Person> cp; // template 3 (enable_if) invalid
}

您可以查看full code

我介绍了一个模板,它通过将第一个模板作为默认值来隐藏第一个模板。您可以在类内部和继承中使用它。

我添加了安全检查以防止使用不同的模板参数实例化您的对象:Object&lt;Type::Car, Type::Person&gt;。为此,我添加了第三个模板参数,它是一个类型模板,默认值为 enable_if。如果您尝试使用不同的模板参数实例化对象,您将收到编译时错误。第二个检查防止你有这样的对象:Object&lt;Type::Car, Object::Car, int&gt;,因为在这种情况下,编译器将回退到要断言的主模板。

没有安全检查就变得更简单了:

enum class Type { Car, Person, Truck };

template<Type TYPE>
struct ObjectConfig;

template<>
struct ObjectConfig<Type::Car>
{ };

template<>
struct ObjectConfig<Type::Person>
{ };

template<Type TYPE, Type DELEGATED_TYPE = TYPE>
struct Object;

template<Type DELEGATED_TYPE>
struct Object<Type::Car, DELEGATED_TYPE>
{
    ObjectConfig<DELEGATED_TYPE> m_params;
};

template<Type DELEGATED_TYPE>
struct Object<Type::Person, DELEGATED_TYPE> : public ObjectConfig<DELEGATED_TYPE>
{ };

int main() {
    Object<Type::Car> c;
    Object<Type::Person> p;
}

【讨论】:

  • 感谢您的回答,但我认为带有安全检查的版本并不完全安全,可以使用以下代码绕过检查:Object<:car type::person void> c2;
【解决方案2】:

我想我找到了一个通用的解决方案。

#include <type_traits>

enum class Type { Car, Person };

template< Type TYPE, typename T = void >
struct Object
{
    static_assert( sizeof( T ) == 0, "Not supported" );
};

template< Type TYPE >
struct ObjectConfig;

template<>
struct ObjectConfig< Type::Car >
{
};


// Version 1 - solved
template< Type TYPE >
struct Object< TYPE, std::enable_if_t< TYPE == Type::Car > >: public ObjectConfig< TYPE > // No emum duplication
{
};

// Version 2 - solved
template< Type TYPE >
struct Object< TYPE, std::enable_if_t< TYPE == Type::Person > >
{
    ObjectConfig< TYPE > m_params; // No emum duplication
};

您可以查看完整的解决方案here (code)

【讨论】:

  • 我认为这个版本是防错的,用户不能用棘手的实例来搞砸它:) 至少对我来说,代码似乎很紧凑:) 请添加你的想法和 cmets,我会接受除非您发现缺陷,否则此版本作为答案。
【解决方案3】:

如果可能,您可以通过组合而不是继承来工作。创建一个内部模板化配置类并向其添加一个成员。

template< Type TYPE>
struct ObjectByComposition
{
    template<typename Type TYPE >
    struct Config{
        /*Whatever*/
    };

    Config<TYPE> m_Config;
};

ObjectByComposition< Type::Car > m_params;

在 OP 回答后编辑:作为内部类的事实当然不是强制性的,重要的是使成员 m_config 模板化为 T 类型。

template< Type TYPE  >
struct ObjectByComposition
{
    ObjectConfig< TYPE> m_Config;
};

ObjectByComposition< Type::Car > m_params;

【讨论】:

  • 我需要明确且独立地专门化 Object 和 ObjectConfig 类(它们有自己的类层次结构,但我对其进行了简化)——这就是内部类不适合的原因。正如您在我原来的问题“版本 2”中看到的那样使用组合,但它不能解决我的问题(我必须写两次枚举值)。
  • 重要的是成员 m_config 是模板化的。它不需要是内部类...
  • 如果还不够(如果可以使用几种类型的ObejctConfig),则需要ObjectConfig的模板模板参数并提供默认值。
  • 根据我之前的评论:“我需要明确且独立地专门化 Object 和 ObjectConfig 类”所以我需要专门化 - 在您的版本中 - ObjectByComposition 类,因为 Car 类型具有与 Person 不同的功能类型。我的整个问题都是关于专业化的,我不知道您的代码如何处理这种情况。我将在问题中提供一个完整的例子,你能用你的版本改进它吗?
  • 您应该回答的问题是:对于给定类型 T 的类 Object 的任何特化是否可以具有不是 Config 特化提供的配置?如果是,那么你不能做你的目标,如果不是,那么我的回答很好。没有什么能阻止你我所说的专门配置。如果您还想专门化 Object,那么您可能会做一个模板类 BaseObject 实现我的建议,并从这个类派生一个 Object 类。然后,如果需要,您可以专攻。
【解决方案4】:

我想我已经解决了版本 2 的问题:

enum class Type { Car, Person };

template< Type TYPE >
struct Object;

template< Type TYPE >
struct ObjectConfig;

template<>
struct ObjectConfig< Type::Car >
{
};

template< typename T >
struct ObjectTypeResolver
{
};

template< template< Type > class OBJ_T, Type TYPE >
struct ObjectTypeResolver< OBJ_T< TYPE > >
{
    static constexpr auto value{ TYPE };
};

// Version 1 - still unsolved
//template<>
//struct Object< Type::Car >: public ObjectConfig< Type::Car > // How could I avoid this duplication???
//{
//};

// Version 2 - solved
template<>
struct Object< Type::Car >
{
    static constexpr Type myType{ ObjectTypeResolver< Object >::value }; // No emum duplication
    ObjectConfig< myType > m_params;
};

您可以查看完整代码here (code)

我使用了以下内容: C++17 标准 17.7.1 本地声明的名称

与普通(非模板)类一样,类模板有一个 注入类名(第 12 条)。可以使用注入的类名 作为模板名称或类型名称。当它与一个 模板参数列表,作为模板的模板参数 模板参数,或作为最终标识符 朋友类模板声明的详细类型说明符,它 指类模板本身。否则等价于 模板名称后跟类的模板参数 .

中包含的模板

在类模板特化或部分的范围内 特化,当注入的类名用作类型名时, 它相当于模板名称后跟 类模板特化或部分的模板参数 .

中包含的专业化

这就是为什么它不能应用于版本1的问题:继承列表超出了类模板的范围。

这部分问题仍然悬而未决。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-05
    • 1970-01-01
    • 2017-01-16
    • 1970-01-01
    相关资源
    最近更新 更多