#include <functional>
#include <iostream>
#include <type_traits>
template<typename T>
struct Provider final {
Provider() = delete;
Provider(const Provider& other) : _callback{ other._callback } {}
Provider(Provider&& other) : _callback{ std::move(other._callback) } {}
Provider& operator=(Provider&& other) {
std::swap(other._callback, _callback);
return *this;
}
Provider& operator=(const Provider& other) {
_callback = other._callback;
return *this;
}
template<typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value>::type, typename = typename std::enable_if<!std::is_same<U, T>::value>::type>
Provider<T>& operator=(Provider<U>&& other) {
std::swap(other._callback, _callback);
return *this;
}
template<typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value>::type, typename = typename std::enable_if<!std::is_same<U, T>::value>::type>
Provider<T>& operator=(const Provider<U>& other) {
_callback = other._callback;
return *this;
}
template<typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value>::type, typename = typename std::enable_if<!std::is_same<U, T>::value>::type>
Provider(const Provider<U>& other) : _callback{ other._callback } {}
template<typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value>::type, typename = typename std::enable_if<!std::is_same<U, T>::value>::type>
Provider(Provider<U>&& other) : _callback{ std::move(other._callback) } {}
template<typename U, typename = typename std::enable_if<std::is_constructible<std::function<T()>, U>::value>::type>
Provider(U callback) : _callback{ callback } {}
template<typename = typename std::enable_if<!std::is_constructible<std::function<T()>, T>::value, T>::type>
Provider(T value) : _callback{[=] { return value; }} {}
template<typename U>
friend struct Provider;
T operator()() const {
return _callback();
}
private:
std::function<T()> _callback;
};
template<typename T>
void doSomething(Provider<T> p) {
std::cout << "My value is:" << p() << std::endl;
}
int main()
{
Provider<int> p1 = 9;
Provider<double> p2 = [] { return 9.4; };
Provider<unsigned int> p3{9};
Provider<float> p4{[]{ return 9.4f; }};
doSomething<unsigned int>(5);
doSomething<float>([] { return 9.5f; });
doSomething<int>(p1);
doSomething<double>(p2);
return 0;
}
I2luY2x1ZGUgPGZ1bmN0aW9uYWw+CiNpbmNsdWRlIDxpb3N0cmVhbT4KI2luY2x1ZGUgPHR5cGVfdHJhaXRzPgoKdGVtcGxhdGU8dHlwZW5hbWUgVD4Kc3RydWN0IFByb3ZpZGVyIGZpbmFsIHsKCVByb3ZpZGVyKCkgPSBkZWxldGU7CglQcm92aWRlcihjb25zdCBQcm92aWRlciYgb3RoZXIpIDogX2NhbGxiYWNreyBvdGhlci5fY2FsbGJhY2sgfSB7fQoJUHJvdmlkZXIoUHJvdmlkZXImJiBvdGhlcikgOiBfY2FsbGJhY2t7IHN0ZDo6bW92ZShvdGhlci5fY2FsbGJhY2spIH0ge30KCglQcm92aWRlciYgb3BlcmF0b3I9KFByb3ZpZGVyJiYgb3RoZXIpIHsKCQlzdGQ6OnN3YXAob3RoZXIuX2NhbGxiYWNrLCBfY2FsbGJhY2spOwoJCXJldHVybiAqdGhpczsKCX0KCglQcm92aWRlciYgb3BlcmF0b3I9KGNvbnN0IFByb3ZpZGVyJiBvdGhlcikgewoJCV9jYWxsYmFjayA9IG90aGVyLl9jYWxsYmFjazsKCQlyZXR1cm4gKnRoaXM7Cgl9CgoJdGVtcGxhdGU8dHlwZW5hbWUgVSwgdHlwZW5hbWUgPSB0eXBlbmFtZSBzdGQ6OmVuYWJsZV9pZjxzdGQ6OmlzX2NvbnZlcnRpYmxlPFUsIFQ+Ojp2YWx1ZT46OnR5cGUsIHR5cGVuYW1lID0gdHlwZW5hbWUgc3RkOjplbmFibGVfaWY8IXN0ZDo6aXNfc2FtZTxVLCBUPjo6dmFsdWU+Ojp0eXBlPgoJUHJvdmlkZXI8VD4mIG9wZXJhdG9yPShQcm92aWRlcjxVPiYmIG90aGVyKSB7CgkJc3RkOjpzd2FwKG90aGVyLl9jYWxsYmFjaywgX2NhbGxiYWNrKTsKCQlyZXR1cm4gKnRoaXM7Cgl9CgoJdGVtcGxhdGU8dHlwZW5hbWUgVSwgdHlwZW5hbWUgPSB0eXBlbmFtZSBzdGQ6OmVuYWJsZV9pZjxzdGQ6OmlzX2NvbnZlcnRpYmxlPFUsIFQ+Ojp2YWx1ZT46OnR5cGUsIHR5cGVuYW1lID0gdHlwZW5hbWUgc3RkOjplbmFibGVfaWY8IXN0ZDo6aXNfc2FtZTxVLCBUPjo6dmFsdWU+Ojp0eXBlPgoJUHJvdmlkZXI8VD4mIG9wZXJhdG9yPShjb25zdCBQcm92aWRlcjxVPiYgb3RoZXIpIHsKCQlfY2FsbGJhY2sgPSBvdGhlci5fY2FsbGJhY2s7CgkJcmV0dXJuICp0aGlzOwoJfQoKCXRlbXBsYXRlPHR5cGVuYW1lIFUsIHR5cGVuYW1lID0gdHlwZW5hbWUgc3RkOjplbmFibGVfaWY8c3RkOjppc19jb252ZXJ0aWJsZTxVLCBUPjo6dmFsdWU+Ojp0eXBlLCB0eXBlbmFtZSA9IHR5cGVuYW1lIHN0ZDo6ZW5hYmxlX2lmPCFzdGQ6OmlzX3NhbWU8VSwgVD46OnZhbHVlPjo6dHlwZT4KCVByb3ZpZGVyKGNvbnN0IFByb3ZpZGVyPFU+JiBvdGhlcikgOiBfY2FsbGJhY2t7IG90aGVyLl9jYWxsYmFjayB9IHt9CgoJdGVtcGxhdGU8dHlwZW5hbWUgVSwgdHlwZW5hbWUgPSB0eXBlbmFtZSBzdGQ6OmVuYWJsZV9pZjxzdGQ6OmlzX2NvbnZlcnRpYmxlPFUsIFQ+Ojp2YWx1ZT46OnR5cGUsIHR5cGVuYW1lID0gdHlwZW5hbWUgc3RkOjplbmFibGVfaWY8IXN0ZDo6aXNfc2FtZTxVLCBUPjo6dmFsdWU+Ojp0eXBlPgoJUHJvdmlkZXIoUHJvdmlkZXI8VT4mJiBvdGhlcikgOiBfY2FsbGJhY2t7IHN0ZDo6bW92ZShvdGhlci5fY2FsbGJhY2spIH0ge30KCgl0ZW1wbGF0ZTx0eXBlbmFtZSBVLCB0eXBlbmFtZSA9IHR5cGVuYW1lIHN0ZDo6ZW5hYmxlX2lmPHN0ZDo6aXNfY29uc3RydWN0aWJsZTxzdGQ6OmZ1bmN0aW9uPFQoKT4sIFU+Ojp2YWx1ZT46OnR5cGU+CglQcm92aWRlcihVIGNhbGxiYWNrKSA6IF9jYWxsYmFja3sgY2FsbGJhY2sgfSB7fQoKCXRlbXBsYXRlPHR5cGVuYW1lID0gdHlwZW5hbWUgc3RkOjplbmFibGVfaWY8IXN0ZDo6aXNfY29uc3RydWN0aWJsZTxzdGQ6OmZ1bmN0aW9uPFQoKT4sIFQ+Ojp2YWx1ZSwgVD46OnR5cGU+CglQcm92aWRlcihUIHZhbHVlKSA6IF9jYWxsYmFja3tbPV0geyByZXR1cm4gdmFsdWU7IH19IHt9CgoJdGVtcGxhdGU8dHlwZW5hbWUgVT4KCWZyaWVuZCBzdHJ1Y3QgUHJvdmlkZXI7CgoJVCBvcGVyYXRvcigpKCkgY29uc3QgewoJCXJldHVybiBfY2FsbGJhY2soKTsKCX0KCnByaXZhdGU6CglzdGQ6OmZ1bmN0aW9uPFQoKT4gX2NhbGxiYWNrOwp9OwoKdGVtcGxhdGU8dHlwZW5hbWUgVD4Kdm9pZCBkb1NvbWV0aGluZyhQcm92aWRlcjxUPiBwKSB7CglzdGQ6OmNvdXQgPDwgIk15IHZhbHVlIGlzOiIgPDwgcCgpIDw8IHN0ZDo6ZW5kbDsKfQoKaW50IG1haW4oKQp7CglQcm92aWRlcjxpbnQ+IHAxID0gOTsKCVByb3ZpZGVyPGRvdWJsZT4gcDIgPSBbXSB7IHJldHVybiA5LjQ7IH07CglQcm92aWRlcjx1bnNpZ25lZCBpbnQ+IHAzezl9OwoJUHJvdmlkZXI8ZmxvYXQ+IHA0e1tdeyByZXR1cm4gOS40ZjsgfX07CgoJZG9Tb21ldGhpbmc8dW5zaWduZWQgaW50Pig1KTsKCWRvU29tZXRoaW5nPGZsb2F0PihbXSB7IHJldHVybiA5LjVmOyB9KTsKCWRvU29tZXRoaW5nPGludD4ocDEpOwoJZG9Tb21ldGhpbmc8ZG91YmxlPihwMik7CgogICAgcmV0dXJuIDA7Cn0KCg==