首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >模板化检查类成员函数是否存在?

模板化检查类成员函数是否存在?
EN

Stack Overflow用户
提问于 2008-11-02 20:10:48
回答 33查看 198.4K关注 0票数 575

是否可以编写一个模板,根据类中是否定义了某个成员函数来更改行为?

下面是我想要写的一个简单的例子:

代码语言:javascript
运行
复制
template<class T>
std::string optionalToString(T* obj)
{
    if (FUNCTION_EXISTS(T->toString))
        return obj->toString();
    else
        return "toString not defined";
}

所以,如果class T定义了toString(),那么它就会使用它;否则,它就不会使用它。

EN

Stack Overflow用户

发布于 2020-09-10 13:26:41

我知道这个问题由来已久,但我认为对于像我这样的人来说,有一个更完整的、也适用于std::vector<>::beginconst重载方法的更新答案会很有用。

基于我后续问题中的answeranswer,这里有一个更完整的答案。请注意,这只适用于C++11和更高版本。

代码语言:javascript
运行
复制
#include <iostream>
#include <vector>

class EmptyClass{};

template <typename T>
class has_begin
{
    private:
    has_begin() = delete;
    
    struct one { char x[1]; };
    struct two { char x[2]; };

    template <typename C> static one test( decltype(void(std::declval<C &>().begin())) * ) ;
    template <typename C> static two test(...);    

public:
    static constexpr bool value = sizeof(test<T>(0)) == sizeof(one);
};
    
int main(int argc, char *argv[])
{
    std::cout << std::boolalpha;
    std::cout << "vector<int>::begin() exists: " << has_begin<std::vector<int>>::value << std::endl;
    std::cout << "EmptyClass::begin() exists: " << has_begin<EmptyClass>::value << std::endl;
    return 0;
}

或者更短的版本:

代码语言:javascript
运行
复制
#include <iostream>
#include <vector>

class EmptyClass{};

template <typename T, typename = void>
struct has_begin : std::false_type {};

template <typename T>
struct has_begin<T, decltype(void(std::declval<T &>().begin()))> : std::true_type {};

int main(int argc, char *argv[])
{
    std::cout << std::boolalpha;
    std::cout << "vector<int>::begin() exists: " << has_begin<std::vector<int>>::value << std::endl;
    std::cout << "EmptyClass exists: " << has_begin<EmptyClass>::value << std::endl;
}

注意,这里必须提供一个完整的示例调用。这意味着,如果我们测试resize方法的存在,那么我们将把resize(0)

深度魔法解释

这个问题的第一个答案使用了test( decltype(&C::helloworld) );然而,当它测试的方法由于常量重载而不明确时,这是有问题的,从而使替换尝试失败。

为了解决这种多义性,我们使用了一个空语句,它可以接受任何参数,因为它总是被转换成一个noop,因此多义性是无效的,只要方法存在,调用就是有效的:

代码语言:javascript
运行
复制
has_begin<T, decltype(void(std::declval<T &>().begin()))>

下面是按顺序发生的事情:我们使用std::declval<T &>()创建一个可调用的值,然后可以调用begin。在此之后,begin的值将作为参数传递给空语句。然后,我们使用内置的decltype检索该空表达式的类型,以便可以将其用作模板类型参数。如果begin不存在,则替换是无效的,并根据SFINAE使用另一个声明。

票数 4
EN
查看全部 33 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/257288

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档