#pragma once

namespace at {

template<template <typename> class F, typename ... Args>
auto dispatch(const Type & the_type, Args&&... args)
    -> decltype(F<double>::CPU(the_type,std::forward<Args>(args)...)) {
    switch(the_type.ID()) {
        case TypeID::CPUByte:
            return F<uint8_t>::CPU(the_type,std::forward<Args>(args)...);
        case TypeID::CPUChar:
            return F<int8_t>::CPU(the_type,std::forward<Args>(args)...);
        case TypeID::CPUDouble:
            return F<double>::CPU(the_type,std::forward<Args>(args)...);
        case TypeID::CPUFloat:
            return F<float>::CPU(the_type,std::forward<Args>(args)...);
        case TypeID::CPUInt:
            return F<int>::CPU(the_type,std::forward<Args>(args)...);
        case TypeID::CPULong:
            return F<int64_t>::CPU(the_type,std::forward<Args>(args)...);
        case TypeID::CPUShort:
            return F<int16_t>::CPU(the_type,std::forward<Args>(args)...);
        case TypeID::CPUHalf:
            return F<Half>::CPU(the_type,std::forward<Args>(args)...);
        default:
            runtime_error("dispatch() not implemented for '%s'",the_type.toString());
    }
}

}
