C ++ : 마지막 인수 이외의 템플릿 인수의 기본값?
문제
다음과 같이 보이는 템플릿 컨테이너 클래스가 있습니다.
template<
class KeyType,
class ValueType,
class KeyCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<KeyType>,
class ValueCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<ValueType>
>
class MyClass
{
[...]
}
즉,이 수업의 객체를 인스턴스화 할 때 여러 가지 방법을 수행 할 수 있습니다.
MyClass<MyKeyType, MyValueType> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor, MyCustomValueCompareFunctor> myObject;
그것들은 모두 좋습니다. 문제는 ValuecompareFunctor 인수의 비 기본 버전을 사용하는 MyClass를 인스턴스화하고 싶을 때 발생하지만 여전히 KeyCompareFunctor 인수의 기본값을 사용하고 싶습니다. 그런 다음 이것을 써야합니다.
MyClass<MyKeyType, MyValueType, AnObnoxiouslyLongSequenceOfCharacters<MyKeyType>, MyCustomValueCompareFunctor> myObject;
내가 세 번째 인수를 어떻게 든 생략하고 이것을 작성할 수 있다면 훨씬 더 편리 할 것입니다.
MyClass<KeyType, ValueType, MyCustomValueCompareFunctor> myObject;
MyCustomValuecompareFunctor는 MyKeyType 유형의 객체가 아닌 유형의 MyValueType의 객체에서만 작동하기 때문에 컴파일러는 적어도 이론적으로 내가 여기서 의미하는 바를 해결할 수있는 것처럼 보입니다.
C ++ 에서이 작업을 수행하는 방법이 있습니까?
해결책
일반적으로 템플릿과 함수 또는 메소드 모두에서 C ++는 기본값을 사용할 수 있습니다. 후행 매개 변수 - 탈출구가 없습니다.
단축하려면 템플릿이나 매크로를 권장합니다 AnObnoxiouslyLongSequenceOfCharacters<MyKeyType>
에게 Foo<MyKeyType>
- 완벽하지는 않지만 아무것도 아닌 것보다 낫습니다.
다른 팁
아니요. 가장 가까운 것은 사용자가 Sentinel 유형을 지정할 수 있도록하는 것입니다. void
- "기본값을 여기에 사용"하고 클래스 내에서 템플릿 메타 마법을 사용합니다. typedef
실제 기본값 인 경우 void
당신에게 주어졌습니다. 그러나 이것은 아마도 가독성 관점에서 좋은 생각이 아닐 것입니다.
매개 변수 부스트 그리고 매개 변수라는 이름이 부스트 그래프를 부스트합니다 템플릿 함수/메소드의 이름 지정 매개 변수를 향한 노력입니다. 그들은 당신이 선호하는 순서대로 주장을 제공 할 기회를줍니다. 일부 인수는 기본값이있는 선택적 일 수 있습니다.
템플릿 인수에 동일한 접근법이 적용될 수 있습니다. n 템플릿 인수 + p 옵션을 갖는 대신 n + 1 템플릿 인수로 클래스를 만듭니다. 마지막은 생략 할 수있는 "이름"매개 변수를 보유합니다.
이 답변은 아직 완성되지 않았지만 좋은 출발이되기를 바랍니다!
대안 옵션은 특성 클래스를 사용하는 것입니다.
template <class KeyType>
class KeyTraits
{
typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType> Compare;
};
template <class ValueType>
class ValueTraits
{
typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType> Compare;
};
template<class KeyType class ValueType>
class MyClass
{
typedef KeyTraits<KeyType>::Compare KeyCompareFunctor;
typedef ValueTraits<ValueType>::Compare KeyCompareFunctor;
};
그런 다음 키에 대해 다른 비교 함수가 필요한 유형이있는 경우 해당 케이스의 KeyTraits 유형을 명시 적으로 전문화하게됩니다. 다음은 우리가 그것을 바꾸는 예입니다 int
:
template <>
class KeyTraits<int>
{
typedef SpecialCompareForInt Cmopare;
};
상속을 사용하고 다음과 같이 작동하는 또 다른 옵션이 있습니다. 마지막 두 인수의 경우, 필요한 유형을 생성하는 데 사용할 수있는 두 개의 멤버 템플릿이있는 클래스에서 사실상 상속되는 클래스를 사용합니다. 상속은 가상이기 때문에 선언 한 Typedefs는 아래에 표시된 것처럼 상속 재산간에 공유됩니다.
template<class KeyType,
class ValueType,
class Pol1 = DefaultArgument,
class Pol2 = DefaultArgument>
class MyClass {
typedef use_policies<Pol1, Pol2> policies;
typedef KeyType key_type;
typedef ValueType value_type;
typedef typename policies::
template apply_key_compare<KeyType>::type
key_compare;
typedef typename policies::
template apply_value_compare<ValueType>::type
value_compare;
};
이제 사용하려는 기본 인수가 제공되는 기본 인수가 제공됩니다. 멤버 템플릿은 키 및 값 유형에 의해 매개 변수화됩니다.
struct VirtualRoot {
template<typename KeyType>
struct apply_key_compare {
typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType>
type;
};
template<typename ValueType>
struct apply_value_compare {
typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType>
type;
};
};
struct DefaultArgument : virtual VirtualRoot { };
template<typename T> struct KeyCompareIs : virtual VirtualRoot {
template<typename KeyType>
struct apply_key_compare {
typedef T type;
};
};
template<typename T> struct ValueCompareIs : virtual VirtualRoot {
template<typename ValueType>
struct apply_value_compare {
typedef T type;
};
};
지금, use_policies
모든 템플릿 인수에서 파생됩니다. 파생 클래스 VirtualRoot
기지에서 멤버를 숨기고, 파생 클래스의 구성원은 기본 구성원보다 우세하며, 상속 트리의 다른 경로에 의해 기본 등급 멤버에 도달 할 수 있지만 사용됩니다.
유형의 객체를 만들지 않기 때문에 가상 상속에 대한 비용을 지불하지 않습니다. use_policies
. 가상 상속 만 사용하여 지배 규칙을 사용합니다.
template<typename B, int>
struct Inherit : B { };
template<class Pol1, class Pol2>
struct use_policies : Inherit<Pol1, 1>, Inherit<Pol2, 2>
{ };
우리는 잠재적으로 같은 클래스에서 두 번 이상 파생되기 때문에 클래스 템플릿을 사용합니다. Inherit
: 같은 클래스를 직접 두 번 상속하는 것은 금지됩니다. 그러나 간접적으로 상속하는 것은 허용됩니다. 이제 다음과 같은 모든 것을 사용할 수 있습니다.
MyClass<int, float> m;
MyClass<float, double, ValueCompareIs< less<double> > > m;