Я немного экспериментирую с чертами типов и специализацией шаблонов. Например:
enum TestEnum
{
VALUE0 = 0,
VALUE1 = 1,
VALUE2 = 2
//... And so on...
};
template<int Value>
class cTestClass;
//specializations
template<>
class cTestClass<VALUE0>
{
static int GetVal() { return VALUE0; }
};
template<>
class cTestClass<VALUE1>
{
static int GetVal() { return VALUE1; }
};
template<>
class cTestClass<VALUE2>
{
static int GetVal() { return VALUE2; }
};
typedef cTestClass<VALUE0> cClassVal0; //(1)
typedef cTestClass<VALUE1> cClassVal1; //(2)
typedef cTestClass<VALUE2> cClassVal2; //(3)
//Later in the code
template<int Value>
cTestClass<Value>* Create()
{
return new cTestClass<Value>(/*..*/);
}
//And using the upper function
cClassVal2* pTestClass = Create<VALUE2>();
Это работает абсолютно нормально. Цель состоит в том, чтобы предоставить пользователям интерфейса возможность не иметь дело с шаблонами и параметрами шаблона (хорошо, кроме использования Создайте()). Это причина для typedefs внизу кода.
Нет, вот чего я хочу добиться:
cTestClass должен иметь одну переменную-член, которая доступна через функции-члены. При определенных обстоятельствах я либо хочу, чтобы пользователь мог изменять переменную-член, либо не изменять переменную-член. Таким образом, в основном это означает две функции-члена, одна из которых возвращает член в виде константной ссылки (не модифицируемой) или не константной (модифицируемой). Проблема в том, что, если обе эти функции-члены предоставлены, у пользователя всегда есть возможность изменить переменную-член. Поэтому я хочу выбрать подходящую функцию-член во время компиляции и просто предоставить одну правильную функцию-член для пользователя.
Единственное решение, которое я нашел, выглядит в основном так:
template<int Value, bool ConstAccess>
class cTestClass;
//specializations
template<>
class cTestClass<VALUE0, true>
{
const std::string& get() const
{
return m_strName;
}
static int GetVal() { return VALUE0; }
private:
std::string m_strName;
};
template<>
class cTestClass<VALUE0, false>
{
std::string& get()
{
return m_strName;
}
static int GetVal() { return VALUE0; }
private:
std::string m_strName;
};
//For every upcoming cTestClass two specializations
typedef cTestClass<VALUE0, true> cConstObjectVal0;
typedef cTestClass<VALUE0, false> cObjectVal0;
//And for the rest...
Помимо того факта, что это действительно кажется ненужным дублированием кода, я всегда должен указывать два typedef для каждого возможного VALUE. Но пользователь не должен сталкиваться с этим выбором, он всегда должен иметь возможность просто использовать типы, как указано выше (см. 1, 2, 3).
Это вообще возможно?
Я немного погуглил и придумал следующий сайт: ACCU :: Введение в черты C ++.
Это объяснение кажется подходящей схемой, но я действительно не могу собрать все воедино.
Другая возможность, которую я нашел, описана здесь: C ++ Шаблон специализации, чтобы обеспечить дополнительную функцию-член? Было бы возможно просто добавить одну функцию, но это все равно не решило бы мою проблему с typedef.
Мы можем попытаться нанять SFINAE:
typedef char True;
typedef long False;
template <typename VALUE0, typename IsConst>
class cTestClass
{
public:
template <typename T, T> struct TypeCheck {};
const std::string& get(TypeCheck<IsConst, True >* dummy = NULL);
std::string& get(TypeCheck<IsConst, False>* dummy = NULL);
}
typedef cTestClass<VALUE0, True> cConstObjectVal0;
typedef cTestClass<VALUE0, False> cObjectVal0;
Я еще не пытался скомпилировать его, но общий принцип состоит в том, чтобы предотвратить одну из функций для правильной компиляции. SFINAE В принципе, компилятор просто выбросит не ту версию.
Других решений пока нет …