【问题标题】:Template Conflict between String and IntString 和 Int 之间的模板冲突
【发布时间】:2018-09-27 10:06:24
【问题描述】:

我有一个使用 json-glib 为 ReST 服务器创建 JSON 文件的程序。该文件有两个字段,即idvalueid 只是 std::string 但值可以是整数、布尔值、字符串(通过std::string od char const *)或浮点数,具体取决于要传输的值。我在c.str() 函数和char * 中遇到问题。

if(std::is_integral<T>::value)
        {
            if(std::is_same<T, bool>::value)
            {
                if(json_builder_add_boolean_value (builder, tagValue) == nullptr)
                {
                    returnMessage = string("json_builder_add_boolean_value was inconsistent in setTag(Boolean). TagName : ") + tagName + string("TagValue : ") + to_string(tagValue);
    #ifdef __DEBUG
                   cerr << returnMessage;
    #endif 
                    return false;
                }
            }
            else
            {
                if(json_builder_add_int_value (builder, tagValue) == nullptr)
                {
                    returnMessage = string("json_builder_add_int_value was inconsistent in setTag(Int). TagName : ") + tagName + string("TagValue : ") + to_string(tagValue);
    #ifdef __DEBUG
                   cerr << returnMessage;
    #endif 
                    return false;
                }
            }
        }
        else if(std::is_floating_point<T>::value)
        {
            if(json_builder_add_double_value (builder, tagValue) == nullptr)
            {
                returnMessage = string("json_builder_add_double_value was inconsistent in setTag(Double). TagName : ") + tagName + string("TagValue : ") + to_string(tagValue);
    #ifdef __DEBUG
               cerr << returnMessage;
    #endif 
                return false;
            }
        }
        else if(std::is_same<T, string>::value or std::is_same<T, const string>::value)
        {
            if(json_builder_add_string_value (builder, tagValue.c_str()) == nullptr)
            {
                returnMessage = string("json_builder_add_string_value was inconsistent in setTag(String). TagName : ") + tagName + string("TagValue : ") + to_string(tagValue);
    #ifdef __DEBUG
               cerr << returnMessage;
    #endif 
                return false;
            }
        }
        else if(std::is_same<T, char *>::value or std::is_same<T, const char *>::value)
        {
            if(json_builder_add_string_value (builder, tagValue) == nullptr)
            {
                returnMessage = string("json_builder_add_string_value was inconsistent in setTag(String). TagName : ") + tagName + string("TagValue : ") + to_string(tagValue);
    #ifdef __DEBUG
               cerr << returnMessage;
    #endif 
                return false;
            }


}

错误:在‘tagValue’中请求成员‘c_str’,它是非类类型‘int’ if(json_builder_add_string_value (builder, tagValue.c_str()) == nullptr)

错误:从“int”到“const gchar* {aka const char*}”的无效转换 [-fpermissive]

【问题讨论】:

  • 您正在寻找if constexpr。普通的if 不会丢弃死代码。
  • 此解决方案从 C++17 开始使用 if constexpr;在它之前,当T 是一个整数时,c_str() 也会被编译;所以错误
  • 我使用的是 C++14。 Raspberry Pi 3 上的 g++ 7.2 MingW 和 g++ 6.2。

标签: c++ templates c++14 sfinae typetraits


【解决方案1】:

我正在使用 C++14

很遗憾。 您不能使用 if constexpr 来解决您的问题,但它是从 C++17 引入的。

无论如何,没有if constexpr,编译器必须编译你函数的每一部分;因此,如果您的tagValuebool,编译器还必须编译不适用于booltagValue.c_str() 调用。

所以错误。

在 C++17 之前,你必须为不同的类型开发不同的函数。

一种可能的解决方案是使用重载和 SFINAE 为三种精确类型(boolstd::string const &amp;char const *)定义三个非模板 foo() 函数

void foo (std::string const & id, bool value)
 {
   // json_builder_add_boolean_value, etc

   std::cout << "-- bool case: " << id << ", " << value << std::endl;
 }

void foo (std::string const & id, std::string const & value)
 {
   // json_builder_add_string_value, etc

   std::cout << "-- std::string case: " << id << ", " << value << std::endl;
 }

void foo (std::string const & id, char const * value)
 {
   // json_builder_add_string_value, etc

   std::cout << "-- char * case: " << id << ", " << value << std::endl;
 }

还有两个模板 foo() 函数,通过 SFINAE 为整数类型(第一个)和浮点类型(第二个)启用

template <typename T>
std::enable_if_t<std::is_integral<T>{}>
   foo (std::string const & id, T const & value)
 {
   // json_builder_add_int_value, etc

   std::cout << "-- integral case: " << id << ", " << value << std::endl;
 }

template <typename T>
std::enable_if_t<std::is_floating_point<T>{}>
   foo (std::string const & id, T const & value)
 {
   // json_builder_add_double_value, etc

   std::cout << "-- floating case: " << id << ", " << value << std::endl;
 }

这么叫

   foo("1", false);
   foo("2", 0L);
   foo("3", 0.0f);
   foo("4", std::string{"zero"});
   foo("5", "zero");

你得到

-- bool case: 1, 0
-- integral case: 2, 0
-- floating case: 3, 0
-- std::string case: 4, zero
-- char * case: 5, zero

观察bool是一个整型,所以可以匹配foo()模板整型和foo()bool特定版本。

在这种情况下,首选精确匹配,因此调用bool 特定版本。

【讨论】:

  • 不幸的是,我必须保持 Raspberry Pi 应用程序和 Windows 应用程序之间的代码兼容性,因此 C++14 是唯一的选择。我考虑过重载模板函数,但缺点是只有一行必须复制所有 377 行。我也在看 SFINAE,但它看起来有点棘手。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-16
  • 2014-09-13
  • 2013-12-31
  • 2015-10-07
  • 2015-12-08
  • 2013-12-20
  • 2021-09-11
相关资源
最近更新 更多