如何减少函数模板特化?
How can I reduce the function template specializations?
我正在尝试编写一个 属性 验证器以在 UE4 中使用,使用他们的反射系统。
我首先想到这个:
class FDataValidator
{
public:
FDataValidator( UObject & object, TArray< FText > & validation_errors ) :
Object( object ),
ValidationResult( validation_errors.Num() == 0 ? EDataValidationResult::Valid : EDataValidationResult::Invalid ),
ObjectClass( Object.GetClass() ),
ValidationErrors( validation_errors )
{}
template < class _TYPE_ >
FDataValidator & GreaterThan( const FName property_name, const _TYPE_ value );
EDataValidationResult Result() const
{
return ValidationResult;
}
private:
template < class _PROPERTY_TYPE_, class _VALUE_TYPE_, class _COMPARATOR_TYPE_ >
FDataValidator & CompareProperty( const FName property_name, const _VALUE_TYPE_ value, _COMPARATOR_TYPE_ comparator = _COMPARATOR_TYPE_() )
{
if ( auto * property = GetTypedProperty< _PROPERTY_TYPE_ >( property_name ) )
{
const auto property_value = property->GetPropertyValue_InContainer( &Object );
if ( !comparator( property_value, value ) )
{
AddError( FText::FromString( FString::Printf( TEXT( "%s must be greater than %f" ), *property_name.ToString(), value ) ) );
}
}
return *this;
}
template < class _PROPERTY_TYPE_ >
_PROPERTY_TYPE_ * GetTypedProperty( const FName property_name )
{
if ( auto * property = ObjectClass->FindPropertyByName( property_name ) )
{
if ( auto * typed_property = Cast< _PROPERTY_TYPE_ >( property ) )
{
return typed_property;
}
}
return nullptr;
}
void AddError( FText text )
{
ValidationErrors.Emplace( text );
ValidationResult = EDataValidationResult::Invalid;
}
UObject & Object;
EDataValidationResult ValidationResult;
UClass * ObjectClass;
TArray< FText > & ValidationErrors;
};
template <>
FDataValidator & FDataValidator::GreaterThan< float >( const FName property_name, const float value )
{
return CompareProperty< UFloatProperty, float, std::greater< float > >( property_name, value );
}
template <>
FDataValidator & FDataValidator::GreaterThan< int >( const FName property_name, const int value )
{
return CompareProperty< UIntProperty, int, std::greater< int > >( property_name, value );
}
我只为 2 种类型实现了 GreaterThan,我想知道我是否可以重构 class 以避免如此多的模板特化。
是否可能有类似的东西,例如我传递 std::greater< _VALUE_TYPE_ >
并让系统推断 _VALUE_TYPE_
是用正确的类型调用 GetTypedProperty
?
class FDataValidator
{
public:
template < class _VALUE_TYPE_ >
FDataValidator & GreaterThan( const FName property_name, const _VALUE_TYPE_ value )
{
return NumericComparator< std::greater< _VALUE_TYPE_ > >( property_name, value );
}
private:
// How to write this to infer for example that _VALUE_TYPE_ is float when passed std::greater< float > ?
template < typename _COMPARATOR_TYPE_ >
FDataValidator & NumericComparator( FName property_name, _VALUE_TYPE_ value, _COMPARATOR_TYPE_ comparator = _COMPARATOR_TYPE_() );
};
template < class _VALUE_TYPE_, class _COMPARATOR_TYPE_ >
FDataValidator & NumericComparator( FName property_name, _VALUE_TYPE_ value, _COMPARATOR_TYPE_ comparator = _COMPARATOR_TYPE_() )
{
return CompareProperty< UFloatProperty, float, std::greater< float > >( property_name, value );
}
谢谢
UFloatProperty
和其他数字类型似乎来自 TProperty_Numeric<T>
inherit。
所以这样的事情可能是一个解决方案:
template <typename T>
FDataValidator& FDataValidator::GreaterThan<T>(const FName property_name, const T value)
{
return CompareProperty<TProperty_Numeric<T>, T, std::greater<T>>(property_name, value);
}
我正在尝试编写一个 属性 验证器以在 UE4 中使用,使用他们的反射系统。 我首先想到这个:
class FDataValidator
{
public:
FDataValidator( UObject & object, TArray< FText > & validation_errors ) :
Object( object ),
ValidationResult( validation_errors.Num() == 0 ? EDataValidationResult::Valid : EDataValidationResult::Invalid ),
ObjectClass( Object.GetClass() ),
ValidationErrors( validation_errors )
{}
template < class _TYPE_ >
FDataValidator & GreaterThan( const FName property_name, const _TYPE_ value );
EDataValidationResult Result() const
{
return ValidationResult;
}
private:
template < class _PROPERTY_TYPE_, class _VALUE_TYPE_, class _COMPARATOR_TYPE_ >
FDataValidator & CompareProperty( const FName property_name, const _VALUE_TYPE_ value, _COMPARATOR_TYPE_ comparator = _COMPARATOR_TYPE_() )
{
if ( auto * property = GetTypedProperty< _PROPERTY_TYPE_ >( property_name ) )
{
const auto property_value = property->GetPropertyValue_InContainer( &Object );
if ( !comparator( property_value, value ) )
{
AddError( FText::FromString( FString::Printf( TEXT( "%s must be greater than %f" ), *property_name.ToString(), value ) ) );
}
}
return *this;
}
template < class _PROPERTY_TYPE_ >
_PROPERTY_TYPE_ * GetTypedProperty( const FName property_name )
{
if ( auto * property = ObjectClass->FindPropertyByName( property_name ) )
{
if ( auto * typed_property = Cast< _PROPERTY_TYPE_ >( property ) )
{
return typed_property;
}
}
return nullptr;
}
void AddError( FText text )
{
ValidationErrors.Emplace( text );
ValidationResult = EDataValidationResult::Invalid;
}
UObject & Object;
EDataValidationResult ValidationResult;
UClass * ObjectClass;
TArray< FText > & ValidationErrors;
};
template <>
FDataValidator & FDataValidator::GreaterThan< float >( const FName property_name, const float value )
{
return CompareProperty< UFloatProperty, float, std::greater< float > >( property_name, value );
}
template <>
FDataValidator & FDataValidator::GreaterThan< int >( const FName property_name, const int value )
{
return CompareProperty< UIntProperty, int, std::greater< int > >( property_name, value );
}
我只为 2 种类型实现了 GreaterThan,我想知道我是否可以重构 class 以避免如此多的模板特化。
是否可能有类似的东西,例如我传递 std::greater< _VALUE_TYPE_ >
并让系统推断 _VALUE_TYPE_
是用正确的类型调用 GetTypedProperty
?
class FDataValidator
{
public:
template < class _VALUE_TYPE_ >
FDataValidator & GreaterThan( const FName property_name, const _VALUE_TYPE_ value )
{
return NumericComparator< std::greater< _VALUE_TYPE_ > >( property_name, value );
}
private:
// How to write this to infer for example that _VALUE_TYPE_ is float when passed std::greater< float > ?
template < typename _COMPARATOR_TYPE_ >
FDataValidator & NumericComparator( FName property_name, _VALUE_TYPE_ value, _COMPARATOR_TYPE_ comparator = _COMPARATOR_TYPE_() );
};
template < class _VALUE_TYPE_, class _COMPARATOR_TYPE_ >
FDataValidator & NumericComparator( FName property_name, _VALUE_TYPE_ value, _COMPARATOR_TYPE_ comparator = _COMPARATOR_TYPE_() )
{
return CompareProperty< UFloatProperty, float, std::greater< float > >( property_name, value );
}
谢谢
UFloatProperty
和其他数字类型似乎来自 TProperty_Numeric<T>
inherit。
所以这样的事情可能是一个解决方案:
template <typename T>
FDataValidator& FDataValidator::GreaterThan<T>(const FName property_name, const T value)
{
return CompareProperty<TProperty_Numeric<T>, T, std::greater<T>>(property_name, value);
}