【问题标题】:C++11 function template specializes as a class method if it existsC++11 函数模板专门作为类方法(如果存在)
【发布时间】:2019-10-18 08:15:34
【问题描述】:

我有这个函数模板:

template <class T>
Json::Value write_json(const T& object);

Tint 时,特化很简单:

template <>
Json::Value write_json(const int& object) {
  Json::Value output;
  output = object;
  return output;
};

但是,对于更复杂的类,我希望它调用一个方法(如果存在):

template <typename T>
struct has_write_json_method {
    template <typename U>
    static constexpr decltype(std::declval<U>().write_json(), bool()) test(int) { return true; };

    template <typename U>
    static constexpr bool test(...) { return false; }

    static constexpr bool value = test<T>(int());
};

template <class T>
typename std::enable_if<has_write_json_method<T>::value, Json::Value>::type write_json(const T& object)  {
    object.write_json();
};

例如,对于 foo 类:

Json::Value foo::write_json(void) { 
  Json::Value output;
  output = 42;
  return output;
};

我想像这样称呼每个班级:

int x_int;
write_json(x_int);
foo x_foo;
write_json(x_foo);

但是,我得到了:

error: call of overloaded 'write_json(const foo&)' is ambiguous

如何消除这种歧义?

【问题讨论】:

  • 您没有显示进行调用的代码。
  • @keith 我认为现在我想做什么更清楚了。

标签: c++ c++11 templates sfinae


【解决方案1】:

您也应该将SFINAE 应用于另一个重载,以避免在T 类型具有write_json 方法时出现歧义。

template <class T>
typename std::enable_if<!has_write_json_method<T>::value, void>::type write_json(const T& object);
//                      ^

LIVE

【讨论】:

    【解决方案2】:

    我会用更简单的方式来写:

    template<class T>
    struct json_helper {   
        static void write_json(const T& t) {
            return t.write_json();
        }
    };
    
    template<class T>
    void write_json(const T& t) {
        return json_helper<T>::write_json(t);
    }
    
    
    template<>
    struct json_helper<int>{
        static void write_json(const int &i) {
        }
    };
    
    struct foo {
        void write_json(void) const { }
    };
    struct bar {};
    
    int main() {
        foo f;
        write_json(f);
        // write_json(bar{}); << this won't work
    }
    

    Live example

    【讨论】:

    • 我喜欢您的 (KISS) 解决方案。但我没有找到处理 std::vector 的方法
    • @Medicalphysicist 这很简单,添加 struct json_helper 的另一个显式实例化: template struct json_helper<:vector>>{...} ;。就是这样
    • 当 write_json 返回我定义的类而不是 void 时,此解决方案存在内存问题(munmap_chunk 错误)。你知道为什么吗?
    • @Medicalphysicist 这似乎不是这个解决方案的问题,只是暗示你在其他地方有错误。当您无效地调用 free/delete 时会发生 munmap_chunk 错误,因此我将使用复制/移动构造函数和析构函数开始搜索
    【解决方案3】:

    你可以做标签调度:

    #include <type_traits>
    
    template <class T>
    void write_json_impl(const T& object, std::true_type)  {
        object.write_json();
    };
    
    template <class T>
    void write_json_impl(const T& object, std::false_type)  {
    };
    
    template <typename T>
    struct has_write_json_method {
        template <typename U>
        static constexpr decltype(std::declval<U>().write_json(), bool()) test(int) { return true; };
    
        template <typename U>
        static constexpr bool test(...) { return false; }
    
        static constexpr bool value = test<T>(int());
    
        // Add this:
        using type = typename std::conditional<value, std::true_type, std::false_type>::type;
        // or this:
        // using type = std::integral_constant<bool, value>;
    };
    
    template <class T>
    void write_json(const T& object)
    {
        return write_json_impl(object, typename has_write_json_method<T>::type{});
    };
    
    struct Foo { void write_json() const {} };
    
    int main()
    {
        Foo f;
        write_json(f);
        write_json(0);
    }
    

    Live.

    【讨论】:

      猜你喜欢
      • 2013-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-01
      相关资源
      最近更新 更多