47455


c++のテンプレートで

[code]

    template<class T>
    T get(std::string str)
    {
    if (std::is_signed<T>)
    {
        return std::stoll(str);
    }
    if(std::is_unsigned_v<T>)
    {
        return std::stoull(str);
    }
    if(std::is_floating_point_v<T>)
    {
        return std::stold(str);
    }
    return T(str);
    }
    
[/code]

みたいなことをコンパイル時に、  
整数なら

[code]

    template<class T>
    T get(std::string str)
    {
    return std::stoll(str);
    }
    
[/code]

浮動小数少数なら

[code]

    template<class T>
    T get(std::string str)
    {
    return std::stold(str);
    }
    
[/code]

それ以外なら

[code]

    template<class T>
    T get(std::string str)
    {
        return T(str);
    }
    
[/code]

のように分けて実装したいのですが  
いちいち型ごとに

[code]

    template<>
    int get<int>(std::string str)
    {
        return std::stold(str);
    }
    
[/code]

とするのは面倒なのでもっと効率的な書き方は存在しませんか？


CC BY-SA 4.0
2018-08-11T15:48:16.527
47452
2018-08-12T05:07:43.453
29398
question
c++ templates
c++ templateの特殊化について


戻り値に`enable_if`を使った

[code]

    template<typename T>
    typename std::enable_if_t<std::is_signed_v<T>, T> get(std::string str)
    {
        return std::stoll(str);
    }
    
    template<typename T>
    typename std::enable_if_t<std::is_unsigned_v<T>, T> get(std::string str)
    {
        return std::stoull(str);
    }
    
    // その他
    template<typename T>
    typename std::enable_if_t<
        !std::is_unsigned_v<T> &&
        !std::is_signed_v<T>,
        T> get(std::string str)
    {
        return T(str);
    }
    
[/code]

のような方法がありますが、これは具体的な型をつかっていないのでtemplateの特殊化ではなく、同名のtemplateを複数定義しているだけです。したがって、その他のケースを扱うところで、既に他で処理されているケースを除外しなければなりません。このため、特別なケースが増えると逆に面倒になってしまいます。また、新たにケースを追加したり削除したりするときにも、ミスをしやすくなります。

C++17が使えるなら、`constexpr if`を使うのが楽でいいと思います。

[code]

    template<typename T>
    T get(std::string str)
    {
        if constexpr(std::is_signed_v<T>) {
            return std::stoll(str);
        }
        else if constexpr(std::is_unsigned_v<T>) {
            return std::stoull(str);
        }
        else {
            return T(str);
        }
    }
    
[/code]


CC BY-SA 4.0
2018-08-11T18:51:19.863
47453
2018-08-11T18:51:19.863
3605
47452
answer


C++11にも対応させるなら以下のように型特性によるオーバーロードを使えばできなくもないですが、C++17以降への対応で良いなら`if
constexpr`文を使った方がはるかに楽ですね。

[code]

    #include <type_traits>
    #include <string>
    #include <iostream>
    
    
    template <class T>
    T get(const std::string &str,
          typename std::enable_if<
              std::is_integral<T>::value && std::is_signed<T>::value
          >::type * = nullptr)
    {
        return std::stoll(str);
    }
    
    template <class T>
    T get(const std::string &str,
          typename std::enable_if<
              std::is_integral<T>::value && std::is_unsigned<T>::value
          >::type * = nullptr)
    {
        return std::stoull(str);
    }
    
    template <class T>
    T get(const std::string &str,
          typename std::enable_if<
              std::is_floating_point<T>::value
          >::type * = nullptr)
    {
        return std::stold(str);
    }
    
    template <class T>
    T get(const std::string &str,
          typename std::enable_if<
              !std::is_integral<T>::value && !std::is_floating_point<T>::value
          >::type * = nullptr)
    {
        return str;
    }
    
    
    int main()
    {
        auto si = get<int>("-123");
        std::cout << "si = " << si << "\n";
    
        auto ui = get<unsigned int>("123");
        std::cout << "ui = " << ui << "\n";
    
        auto df = get<double>("123.4");
        std::cout << "df = " << df << "\n";
    
        auto str = get<std::string>("xyz");
        std::cout << "str = " << str << "\n";
    }
    
[/code]


CC BY-SA 4.0
2018-08-12T03:17:17.520
47455
2018-08-12T05:07:43.453
2018-08-12T05:07:43.453
7291
7291
47452
answer