templates — Реплицируйте перегруженный тип возвращаемого значения Haskell (через классы типов) в переполнении стека

В Haskell классы типов позволяют элегантно перегружать функции в зависимости от типа возвращаемого значения. Реплицировать это в C ++ довольно просто для случаев, когда оба аргумента и возвращаемый тип перегружены с использованием шаблонов (пример A):

template <typename In, typename Out> Out f(In value);

template <typename T> int f<T, int>(T value) {
...
}

Что соответствует Хаскеллу:

class F a b where
f :: a -> b

Вы можете даже перегрузить только тип возвращаемого значения в большинстве функций (пример B):

template <typename Out> Out f(SomeClass const &value);

template <> inline int f(SomeClass const &value) {
return value.asInt();
}

template <> inline float f(SomClass const &value) {
return value.asFloat();
}

Что соответствует чему-то вроде:

class F a where
f :: SomeData -> a

Но то, что я хотел бы сделать, это изменить последний пример для перегрузки типов более высокого порядка, а именно шаблонных структур в C ++. То есть я хотел бы иметь возможность написать специализацию, похожую на следующий Haskell:

data Foo a = Foo a

instance F (Foo a) where
f someData = Foo $ ...

Как можно написать шаблон с этой функциональностью (возможно ли это)?


Для справки, я собираюсь использовать это для написания шаблонных функций для моста Lua / C ++. Идея состоит в том, чтобы соединить функции Lua и C ++ с помощью перегруженной функции. interpretValue это автоматически выталкивает или конвертирует из стека Lua. Для простых типов, имеющих прямое встроенное представление Lua, это достаточно просто с помощью кода, такого как пример B.

Для более сложных типов я также пишу template <typename T> struct Data чтобы управлять управлением памятью для объектов (мост между GC Lua и C ++ стороны рефконт), и я надеялся, что смогу перегрузить interpretValue так что он может автоматически обернуть указатель пользовательских данных в Data<T>, Я попытался использовать следующее, но clang выдал ошибку «вызов функции неоднозначен»:

template <typename U> inline U &interpretValue(lua_State *state, int index) {
return Data<U>::storedValueFromLuaStack(state, index);
}

template <typename U> inline Data<U> interpretValue(lua_State *state, int index) {
return Data<U>::fromLuaStack(state, index);
}

Спасибо!

1

Решение

Ну, вы можете написать одну функцию:

template <class U>
interpretValueReturnType<U> interpretValue(lua_State *state, int index)
{
return interpretValueReturnType<U>(state, index);
}

Затем вам нужно написать этот тип возвращаемого значения с помощью операторов приведения, так что вы получите то, что хотите:

template <class U>
class interpretValueReturnType
{
public:
interpretValueReturnType(lua_State *state, int index) : state(state), index(index) {}

operator U& () &&
{
return Data<U>::storedValueFromLuaStack(state, index);
}

operator Data<U> () &&
{
return Data<U>::fromLuaStack(state, index);
}
private:
lua_State *state;
int index;
};

Увидеть ideone:

int main() {
lua_State *state;
int& a = interpretValue<int>(state, 1);
Data<int> b = interpretValue<int>(state, 1);
}

Это смешно && в конце operatorОбъявления s предназначены для того, чтобы немного усложнить сохранение результата этой функции и использовать его позже — как здесь:

    auto c = interpretValue<float>(state, 1);
float& d = c; // not compile

Нужно использовать std::move так как && означает, что функция может использоваться только для ссылок rvalue:

    auto c = interpretValue<float>(state, 1);
float& d = std::move(c);
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]