C++11 如何创建模板函数以将基元和 std::vector 转换为具有最小专业化的 std::string?

发布于 2025-01-16 11:57:14 字数 7508 浏览 4 评论 0原文

我卡住的地方已经在标题中描述了。

但是,也许我的全球问题还有另一种解决方案。

有模板基类,它可以完成一些工作,我需要打印结果以进行调试。


template<typename ResultType>

class Foo

{

public:

    void PrintResult()

    {

        std::cout<<toString<ResultType>(result)<<std::endl;

    }

    virtual void Do(std::vector<void*> args)=0;

    virtual ~Foo(){}

protected:

    ResultType result;

};

我主要需要打印基元、std::string 和基元、字符串或向量的 std::vector。

我决定为此使用模板,但我无法专门化 std::vector 的模板。我不知道为什么它选择了错误的重载。


#include <iostream>

#include <sstream>

#include <vector>

template <typename T>

std::string toString(const T& obj)

{

    return std::to_string(obj);

}

template <typename T>

std::string toString(const std::vector<T>& obj)

{

    std::stringstream ss;

    ss<<"[";

    for(size_t i=0;i<obj.size();++i)

    {

        ss<<toString<T>(obj[i]);

        if(i!=obj.size()-1)

            ss<<", ";

    }

    ss<<"]";

    return ss.str();

}

int main()

{

    int intValue = 42;

    std::vector<int> vectorOfInts;

    std::vector<std::vector<double>> vectorOfVectorsOfDoubles;

    std::cout<<toString<int>(intValue)<<std::endl;

    std::cout<<toString<std::vector<int>>(vectorOfInts)<<std::endl;

    std::cout<<toString<std::vector<std::vector<double>>>(vectorOfVectorsOfDoubles)<<std::endl;

    return EXIT_SUCCESS;

}

错误:


./main.cpp:-1: In instantiation of ‘std::__cxx11::string toString(const T&) [with T = std::vector<int>; std::__cxx11::string = std::__cxx11::basic_string<char>]’:

./main.cpp:33: required from here

./main.cpp:8: error: no matching function for call to ‘to_string(const std::vector<int>&)’

     return std::to_string(obj);

            ~~~~~~~~~~~~~~^~~~~

./main.cpp:-1: In instantiation of ‘std::__cxx11::string toString(const T&) [with T = std::vector<std::vector<double> >; std::__cxx11::string = std::__cxx11::basic_string<char>]’:

./main.cpp:34: required from here

./main.cpp:8: error: no matching function for call to ‘to_string(const std::vector<std::vector<double> >&)’

     return std::to_string(obj);

            ~~~~~~~~~~~~~~^~~~~

编译器:

GCC 4.8(C++,x86 64位)

是否有可能不使用所有基元和向量专门化模板函数?

我尝试调整解决方案 C++ 如何使用向量专门化模板?修复了 c++11 的问题 https://ru.stackoverflow.com/questions/500735/stdenable-if-t

但是我仍然收到错误:

#include <iostream>
#include <sstream>
#include <vector>
#include <type_traits>

template<bool C, class T = void>
using enable_if_t = typename std::enable_if<C, T>::type;

template<typename T>
struct is_vector
{
    static constexpr bool value = false;
};

template<template<typename...> class C, typename U>
struct is_vector<C<U>>
{
    static constexpr bool value =
        std::is_same<C<U>,std::vector<U>>::value;
};

template <typename T>
enable_if_t<!is_vector<T>::value,std::string> toString(T& obj)
{
    return std::to_string(obj);
}

template <typename T>
enable_if_t<is_vector<T>::value,std::string> toString(std::vector<T>& obj)
{
    std::stringstream ss;
    ss<<"[";
    for(size_t i=0;i<obj.size();++i)
    {
        ss<<toString<T>(obj[i]);
        if(i!=obj.size()-1)
            ss<<", ";
    }
    ss<<"]";
    return ss.str();
}

int main()
{
    int intValue = 42;
    std::vector<int> vectorOfInts;
    std::vector<std::vector<double>> vectorOfVectorsOfDoubles;

    std::cout<<toString<int>(intValue)<<std::endl;
    std::cout<<toString<std::vector<int>>(vectorOfInts)<<std::endl;
    std::cout<<toString<std::vector<std::vector<double>>>(vectorOfVectorsOfDoubles)<<std::endl;
    return EXIT_SUCCESS;
}
./main.cpp:-1: In function ‘int main()’:
./main.cpp:50: error: no matching function for call to ‘toString<std::vector<int, std::allocator<int> > >(std::vector<int>&)’
     std::cout<<toString<std::vector<int>>(vectorOfInts)<<std::endl;
                                                       ^
./main.cpp:23: candidate: template<class T> enable_if_t<(! is_vector<T>::value), std::__cxx11::basic_string<char> > toString(T&)
 enable_if_t<!is_vector<T>::value,std::string> toString(T& obj)
                                               ^~~~~~~~
./main.cpp:23: note:   template argument deduction/substitution failed:
./main.cpp:29: candidate: template<class T> enable_if_t<is_vector<T>::value, std::__cxx11::basic_string<char> > toString(std::vector<T>&)
 enable_if_t<is_vector<T>::value,std::string> toString(std::vector<T>& obj)
                                              ^~~~~~~~
./main.cpp:29: note:   template argument deduction/substitution failed:
./main.cpp:50: note:   cannot convert ‘vectorOfInts’ (type ‘std::vector<int>’) to type ‘std::vector<std::vector<int>, std::allocator<std::vector<int> > >&’
     std::cout<<toString<std::vector<int>>(vectorOfInts)<<std::endl;
                                                       ^
./main.cpp:51: error: no matching function for call to ‘toString<std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > >(std::vector<std::vector<double> >&)’
     std::cout<<toString<std::vector<std::vector<double>>>(vectorOfVectorsOfDoubles)<<std::endl;
                                                                                   ^
./main.cpp:23: candidate: template<class T> enable_if_t<(! is_vector<T>::value), std::__cxx11::basic_string<char> > toString(T&)
 enable_if_t<!is_vector<T>::value,std::string> toString(T& obj)
                                               ^~~~~~~~
./main.cpp:23: note:   template argument deduction/substitution failed:
./main.cpp:29: candidate: template<class T> enable_if_t<is_vector<T>::value, std::__cxx11::basic_string<char> > toString(std::vector<T>&)
 enable_if_t<is_vector<T>::value,std::string> toString(std::vector<T>& obj)
                                              ^~~~~~~~
./main.cpp:29: note:   template argument deduction/substitution failed:
./main.cpp:51: note:   cannot convert ‘vectorOfVectorsOfDoubles’ (type ‘std::vector<std::vector<double> >’) to type ‘std::vector<std::vector<std::vector<double> >, std::allocator<std::vector<std::vector<double> > > >&’
     std::cout<<toString<std::vector<std::vector<double>>>(vectorOfVectorsOfDoubles)<<std::endl;
                                                                                   ^

The point where I stuck is described in the title.

But, maybe, there are another solution of my global problem.

There are template base class, which does some work, and I need to print results for debugging purposes.


template<typename ResultType>

class Foo

{

public:

    void PrintResult()

    {

        std::cout<<toString<ResultType>(result)<<std::endl;

    }

    virtual void Do(std::vector<void*> args)=0;

    virtual ~Foo(){}

protected:

    ResultType result;

};

I need mostly to print primitives, std::string, and std::vector of primitives, strings or vectors.

I decided to use templates for this, but I can not specialize template for std::vector. I don't know why it chooses wrong overload.


#include <iostream>

#include <sstream>

#include <vector>

template <typename T>

std::string toString(const T& obj)

{

    return std::to_string(obj);

}

template <typename T>

std::string toString(const std::vector<T>& obj)

{

    std::stringstream ss;

    ss<<"[";

    for(size_t i=0;i<obj.size();++i)

    {

        ss<<toString<T>(obj[i]);

        if(i!=obj.size()-1)

            ss<<", ";

    }

    ss<<"]";

    return ss.str();

}

int main()

{

    int intValue = 42;

    std::vector<int> vectorOfInts;

    std::vector<std::vector<double>> vectorOfVectorsOfDoubles;

    std::cout<<toString<int>(intValue)<<std::endl;

    std::cout<<toString<std::vector<int>>(vectorOfInts)<<std::endl;

    std::cout<<toString<std::vector<std::vector<double>>>(vectorOfVectorsOfDoubles)<<std::endl;

    return EXIT_SUCCESS;

}

Errors:


./main.cpp:-1: In instantiation of ‘std::__cxx11::string toString(const T&) [with T = std::vector<int>; std::__cxx11::string = std::__cxx11::basic_string<char>]’:

./main.cpp:33: required from here

./main.cpp:8: error: no matching function for call to ‘to_string(const std::vector<int>&)’

     return std::to_string(obj);

            ~~~~~~~~~~~~~~^~~~~

./main.cpp:-1: In instantiation of ‘std::__cxx11::string toString(const T&) [with T = std::vector<std::vector<double> >; std::__cxx11::string = std::__cxx11::basic_string<char>]’:

./main.cpp:34: required from here

./main.cpp:8: error: no matching function for call to ‘to_string(const std::vector<std::vector<double> >&)’

     return std::to_string(obj);

            ~~~~~~~~~~~~~~^~~~~

Compiler:

GCC 4.8 (C++, x86 64bit)

Is there any possibilities not to specialize template function with all primitives and vectors?

I tried adapt solution from
C++ How to specialize a template using vector<T>?
with fix for c++11 from
https://ru.stackoverflow.com/questions/500735/stdenable-if-t

But I still get errors:

#include <iostream>
#include <sstream>
#include <vector>
#include <type_traits>

template<bool C, class T = void>
using enable_if_t = typename std::enable_if<C, T>::type;

template<typename T>
struct is_vector
{
    static constexpr bool value = false;
};

template<template<typename...> class C, typename U>
struct is_vector<C<U>>
{
    static constexpr bool value =
        std::is_same<C<U>,std::vector<U>>::value;
};

template <typename T>
enable_if_t<!is_vector<T>::value,std::string> toString(T& obj)
{
    return std::to_string(obj);
}

template <typename T>
enable_if_t<is_vector<T>::value,std::string> toString(std::vector<T>& obj)
{
    std::stringstream ss;
    ss<<"[";
    for(size_t i=0;i<obj.size();++i)
    {
        ss<<toString<T>(obj[i]);
        if(i!=obj.size()-1)
            ss<<", ";
    }
    ss<<"]";
    return ss.str();
}

int main()
{
    int intValue = 42;
    std::vector<int> vectorOfInts;
    std::vector<std::vector<double>> vectorOfVectorsOfDoubles;

    std::cout<<toString<int>(intValue)<<std::endl;
    std::cout<<toString<std::vector<int>>(vectorOfInts)<<std::endl;
    std::cout<<toString<std::vector<std::vector<double>>>(vectorOfVectorsOfDoubles)<<std::endl;
    return EXIT_SUCCESS;
}
./main.cpp:-1: In function ‘int main()’:
./main.cpp:50: error: no matching function for call to ‘toString<std::vector<int, std::allocator<int> > >(std::vector<int>&)’
     std::cout<<toString<std::vector<int>>(vectorOfInts)<<std::endl;
                                                       ^
./main.cpp:23: candidate: template<class T> enable_if_t<(! is_vector<T>::value), std::__cxx11::basic_string<char> > toString(T&)
 enable_if_t<!is_vector<T>::value,std::string> toString(T& obj)
                                               ^~~~~~~~
./main.cpp:23: note:   template argument deduction/substitution failed:
./main.cpp:29: candidate: template<class T> enable_if_t<is_vector<T>::value, std::__cxx11::basic_string<char> > toString(std::vector<T>&)
 enable_if_t<is_vector<T>::value,std::string> toString(std::vector<T>& obj)
                                              ^~~~~~~~
./main.cpp:29: note:   template argument deduction/substitution failed:
./main.cpp:50: note:   cannot convert ‘vectorOfInts’ (type ‘std::vector<int>’) to type ‘std::vector<std::vector<int>, std::allocator<std::vector<int> > >&’
     std::cout<<toString<std::vector<int>>(vectorOfInts)<<std::endl;
                                                       ^
./main.cpp:51: error: no matching function for call to ‘toString<std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > >(std::vector<std::vector<double> >&)’
     std::cout<<toString<std::vector<std::vector<double>>>(vectorOfVectorsOfDoubles)<<std::endl;
                                                                                   ^
./main.cpp:23: candidate: template<class T> enable_if_t<(! is_vector<T>::value), std::__cxx11::basic_string<char> > toString(T&)
 enable_if_t<!is_vector<T>::value,std::string> toString(T& obj)
                                               ^~~~~~~~
./main.cpp:23: note:   template argument deduction/substitution failed:
./main.cpp:29: candidate: template<class T> enable_if_t<is_vector<T>::value, std::__cxx11::basic_string<char> > toString(std::vector<T>&)
 enable_if_t<is_vector<T>::value,std::string> toString(std::vector<T>& obj)
                                              ^~~~~~~~
./main.cpp:29: note:   template argument deduction/substitution failed:
./main.cpp:51: note:   cannot convert ‘vectorOfVectorsOfDoubles’ (type ‘std::vector<std::vector<double> >’) to type ‘std::vector<std::vector<std::vector<double> >, std::allocator<std::vector<std::vector<double> > > >&’
     std::cout<<toString<std::vector<std::vector<double>>>(vectorOfVectorsOfDoubles)<<std::endl;
                                                                                   ^

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情独悲 2025-01-23 11:57:14

您为函数调用显式选择了错误的模板实例化。如果您删除模板参数列表并让编译器自动推导它们,则它可以工作:

编译器资源管理器

#include <iostream>
#include <sstream>
#include <vector>

template <typename T>
std::string toString(const T& obj)
{
    return std::to_string(obj); // <- no template param list
}

template <typename T>
std::string toString(const std::vector<T>& obj)
{
    std::stringstream ss;
    ss<<"[";
    for(size_t i=0;i<obj.size();++i)
    {
        ss<<toString(obj[i]); // <- no template param list
        if(i!=obj.size()-1)
            ss<<", ";
    }
    ss<<"]";
    return ss.str();
}

template<typename ResultType>
class Foo
{
public:
    void PrintResult()
    {
        std::cout << toString(result)<<std::endl; // <- no template param list
    }
    virtual void Do(std::vector<void*> args)=0;
    virtual ~Foo(){}
protected:
    ResultType result;
};


int main()
{
    int intValue = 42;
    std::vector<int> vectorOfInts;
    std::vector<std::vector<double>> vectorOfVectorsOfDoubles;
    std::cout<<toString<int>(intValue)<<std::endl; // <- no template param list
    std::cout<<toString(vectorOfInts)<<std::endl; // <- no template param list
    std::cout<<toString(vectorOfVectorsOfDoubles)<<std::endl; // <- no template param list
    return EXIT_SUCCESS;
}

You are explicitly selecting the wrong template instantiations for your function calls. If you remove the template parameter lists and let the compiler deduce them automatically, it works:

Compiler explorer

#include <iostream>
#include <sstream>
#include <vector>

template <typename T>
std::string toString(const T& obj)
{
    return std::to_string(obj); // <- no template param list
}

template <typename T>
std::string toString(const std::vector<T>& obj)
{
    std::stringstream ss;
    ss<<"[";
    for(size_t i=0;i<obj.size();++i)
    {
        ss<<toString(obj[i]); // <- no template param list
        if(i!=obj.size()-1)
            ss<<", ";
    }
    ss<<"]";
    return ss.str();
}

template<typename ResultType>
class Foo
{
public:
    void PrintResult()
    {
        std::cout << toString(result)<<std::endl; // <- no template param list
    }
    virtual void Do(std::vector<void*> args)=0;
    virtual ~Foo(){}
protected:
    ResultType result;
};


int main()
{
    int intValue = 42;
    std::vector<int> vectorOfInts;
    std::vector<std::vector<double>> vectorOfVectorsOfDoubles;
    std::cout<<toString<int>(intValue)<<std::endl; // <- no template param list
    std::cout<<toString(vectorOfInts)<<std::endl; // <- no template param list
    std::cout<<toString(vectorOfVectorsOfDoubles)<<std::endl; // <- no template param list
    return EXIT_SUCCESS;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文