代码之家  ›  专栏  ›  技术社区  ›  qeatzy

基于C++类型的内置类型调度

  •  3
  • qeatzy  · 技术社区  · 6 年前

    我需要一个dispatcher函数,如下所示

    template<typename T>
    T dispatcher() {
        // if T is double
        return _func_double();
        // if T is int
        return _func_int();
        // if T is char*
        return _func_char_pointer();
    }
    

    // some code that use above dispatcher
    template<typename T1, typename T2, typename T3>
    void do_multiple_thing(T1 *a1, T2 *a2, T2 *a3) {
        *a1 = dispatcher<T1>();
        *a2 = dispatcher<T2>();
        *a3 = dispatcher<T3>();
    }
    

    你能告诉我怎么做到吗?

    附笔。

    -预处理和模板逼近都是可以接受的。

    4 回复  |  直到 6 年前
        1
  •  5
  •   Jarod42    6 年前

    如果有C++ 17的编译器支持代码的这个片段应该工作:

    template<typename T>
    T dispatcher() {
        // if T is double
        if constexpr (std::is_same<T, double>::value)
            return _func_double();
        // if T is int
        if constexpr (std::is_same<T, int>::value)
            return _func_int();
        // if T is char*
        if constexpr (std::is_same<T, char*>::value)
            return _func_char_pointer();
    }
    

    //only needed for static assert
    template<typename T>
    struct always_false : std::false_type {};
    
    
    template<typename T>
    T dispatcher() 
    { 
    //to make sure that on type you didn't overload you will have exception
        throw std::exception("This type was not overloaded")
    //static assert that will provide compile time error
        static_assert(always_false<T>::value , "You must specialize dispatcher for your type");
    }
    //or to get compile time error without static assert 
    template<typename T>
    T dispatcher() = delete; //the simplest solution
    
    template<>
    double dispatcher<double>() 
    {
        return _func_double();
    }
    //... and so on for all other functions
    
        2
  •  4
  •   Jarod42    6 年前

    在C++ 17中,如果CONTXPR和 std::is_same :

    template<typename T>
    T dispatcher() {
        if constexpr (std::is_same<T, double>::value) {
            return _func_double();
        } else if constexpr (std::is_same<T, int>::value) {
            return _func_int();
        } else if constexpr (std::is_same<T, char*>::value) {
            return _func_char_pointer();
        } else {
            return {}; // or static_assert(always_false<T>::value); ?
        }
    }
    

    template<typename T>
    T dispatcher() {
        return {}; // or static_assert(always_false<T>::value); ?
    }
    
    template<>
    double dispatcher() {
        return _func_double();
    }
    
    template<>
    int dispatcher() {
        return _func_int();
    }
    
    template<>
    char* dispatcher() {
        return _func_char_pointer();
    }
    

    template<typename T> struct tag {};
    
    
    template<typename T>
    T dispatcher(tag<T>) = delete; // or { return {}; } ?
    
    double dispatcher(tag<double>) { return _func_double(); }
    
    int dispatcher(tag<int>) { return _func_int(); }
    
    char* dispatcher(tag<char*>) { return _func_char_pointer(); }
    
    // some code that use above dispatcher
    template<typename T1, typename T2, typename T3>
    void do_multiple_thing(T1 *a1, T2 *a2, T2 *a3) {
        *a1 = dispatcher(tag<T1>());
        *a2 = dispatcher(tag<T2>());
        *a3 = dispatcher(tag<T3>());
    }
    
        3
  •  3
  •   Marek R    6 年前
    template <typename T>
    T fetch_magic_value();
    
    template <>
    int fetch_magic_value<int>() { return 23; }
    
    template <>
    char fetch_magic_value<char>() { return ' '; }
    
    template <>
    std::string fetch_magic_value<std::string>() { return "tada"; }
    
    template<typename T>
    void do_multiple_thing(T *x) {
      *x = fetch_magic_value<T>();
    }
    
    template<typename T, typename... Args>
    void do_multiple_thing(T *first, Args *...args)
    {
        do_multiple_thing(first);
        do_multiple_thing(args...);
    }
    

    https://wandbox.org/permlink/v2NMhoy8v3q5VhRf

    C++ 17版: https://wandbox.org/permlink/0pi08jvYF5vlIpud

        4
  •  1
  •   Hagai Akibayov    6 年前

    // calls the first function that has return type `T` with no arguments
    template <class T, class F, class... Fs>
    constexpr T call_by_return_type(F&& f, Fs&&... fs) {
        if constexpr (std::is_same_v<T, std::invoke_result_t<F>>) {
            return f();
        } else if constexpr (sizeof...(fs) > 0) {
            return call_by_return_type<T>(std::forward<Fs>(fs)...);
        } else {
            static_assert(
                sizeof(T) == 0,
                "`T` must match at least one function's return type"
            );
        }
    }
    

    然后,您可以将dispatchers创建为函数的组合(可以是不带参数调用的任何函数对象):

    template <class T>
    constexpr T dispatcher() {
        return call_by_return_type<T>(
            _func_double,
            _func_int,
            _func_char_pointer
        );
    }
    

    Example in godbolt.org


    我以为你已经 _func_<return-type> 需要分组以形成分派器的函数,否则我可以考虑更优雅的接口。