模板,decltype和非classtypes

3 c++ templates decltype c++11

我有一个像这样的函数定义

template <typename T>
auto print(T t) -> decltype(t.print()) {
    return t.print();
}
Run Code Online (Sandbox Code Playgroud)

这个想法是参数必须是类型,T并且必须具有该print函数.这个print函数可以返回任何东西,解释了它的需要decltype.例如,您可以这样做:

struct Foo
{
    int print()
    {
        return 42;
    }
};

struct Bar
{
    std::string print()
    {
        return "The answer...";
    }
};

...

std::cout << print(Foo()) << std::endl;    
std::cout << print(Bar()) << std::endl;
/* outputs: 
42
The answer...
*/
Run Code Online (Sandbox Code Playgroud)

我读到模板不能进行运行时实例化,并且您可以从类派生类,然后确定它们的类型以查看要使用的模板参数.但是,我如何为一个non-class类型做这个?这个想法是能够:

template <typename T>
T print(T t) {
    return t;
}
Run Code Online (Sandbox Code Playgroud)

同样,但这给了我模糊的过载错误.资格不起作用,即print<Foo>.另一个得到的问题是,如果我有一个类似的仿函数:

struct Foo
{
  virtual int print();
  operator int() const
  {
    return 42;
  }
};
Run Code Online (Sandbox Code Playgroud)

它现在如何决定?

所以我的问题是,是否可以使用模板解决所有这些歧义,或者我是否必须编写一堆冗余代码?

测试

我逐步添加测试,从下面复制/粘贴每个编辑的解决方案.结果如下:

使用以下课程:

struct Foo
{
    int print()
    {
        return 42;
    }

    operator int() const
    {
        return 32;
    }
};

struct Bar
{
    std::string print()
    {
        return "The answer...";
    }

    operator int() const
    {
        return (int)Foo();
    }
};

struct Baz
{
    operator std::string() const
    {
        return std::string("The answer...");
    }
};
Run Code Online (Sandbox Code Playgroud)

以下测试输出:

std::cout << print(Foo()) << std::endl;    
std::cout << print(Bar()) << std::endl;
std::cout << print(42) << std::endl;
std::cout << print((int)Foo()) << std::endl;
std::cout << print("The answer...") << std::endl;
std::cout << print(std::string("The answer...")) << std::endl;
std::cout << print((int)Bar()) << std::endl;
std::cout << print((std::string)Baz()) << std::endl;
Run Code Online (Sandbox Code Playgroud)

两者都正确输出:

42
The answer...
42
32
The answer...
The answer...
32
The answer...
Run Code Online (Sandbox Code Playgroud)

And*_*owl 5

您可以采用以下方法,print()如果存在这样的成员函数,则在输入上调用成员函数,否则它将返回输入本身:

namespace detail
{
    template<typename T, typename = void>
    struct print_helper
    {
        static T print(T t) {
            return t;
        }
    };

    template<typename T>
    struct print_helper<T, decltype(std::declval<T>().print(), (void)0)>
    {
        static auto print(T t) -> decltype(t.print()) {
            return t.print();
        }
    };
}

template<typename T>
auto print(T t) -> decltype(detail::print_helper<T>::print(t))
{
    return detail::print_helper<T>::print(t);
}
Run Code Online (Sandbox Code Playgroud)

这是一个实例.