C++ 如何转发对成员函数模板的调用,该模板可以是常量,也可以是非常量,具体取决于模板类型?

C++ 如何转发对成员函数模板的调用,该模板可以是常量,也可以是非常量,具体取决于模板类型?,c++,c++14,template-meta-programming,C++,C++14,Template Meta Programming,我有一些类似的东西(将示例简化到相关点) 很明显,Bar::constFn不会编译,因为它调用非常量函数Foo::Nested::get——即使TypeA满足someTrait并最终再次调用const函数constepr Foo::get()const 暂时不考虑constexpr,如何在嵌套类的函数模板中传播被调用函数的constess?我试着简单地用一个常量和非常量版本的Nested::get重载它,它解决了macOS上的叮当声,但在Windows上的Visual Studio 2015中使

我有一些类似的东西(将示例简化到相关点)

很明显,
Bar::constFn
不会编译,因为它调用非常量函数
Foo::Nested::get
——即使
TypeA
满足
someTrait
并最终再次调用const函数
constepr Foo::get()const

暂时不考虑constexpr,如何在嵌套类的函数模板中传播被调用函数的constess?我试着简单地用一个常量和非常量版本的
Nested::get
重载它,它解决了macOS上的叮当声,但在Windows上的Visual Studio 2015中使用MSVC失败了,不幸的是,这是一个必需的构建目标

请注意,原始示例包含的不仅仅是两个版本的
Foo::get
,因此我希望避免重复
Foo::Nested
中的所有版本,但如果可能,可以使用一个或两个函数模板转发它

编辑:我尝试使用该提案

template <typename T>
constexpr auto get() const -> decltype(foo.get<T>()) { return foo.get<T>(); }

template <typename T>
constexpr auto get() -> decltype(foo.get<T>()) { return foo.get<T>(); }

模板
constexpr auto get()const->decltype(foo.get()){return foo.get();}
模板
constexpr auto get()->decltype(foo.get()){return foo.get();}

对于当前的MSVC版本,它似乎编译得很好,但在Visual Studio 2015 MSVC 19.0中失败,因此这是没有选项的。首先,您需要
启用\u if::type
,SFINAE才能工作

要回答您的问题,您需要重载
Nested::get

#include <type_traits>

struct Foo
{
    template <typename T>
    constexpr std::enable_if_t<std::is_integral_v<T>, T>&
    get() const
    { return something(); }

    template <typename T>
    std::enable_if_t<std::is_floating_point_v<T>, T>&
    get()
    { return somethingDifferent(); }

    int& something() const;
    float& somethingDifferent();

    class Nested
    {
    public:
        Nested();

        template <typename T>
        constexpr std::enable_if_t<std::is_integral_v<T>, T>&
        get() const { return foo.get<T>(); }

        template <typename T>
        std::enable_if_t<std::is_floating_point_v<T>, T>&
        get() { return foo.get<T>(); }

    private:
        Foo& foo;
    };
};
#包括
结构Foo
{
模板
constexpr std::启用&
get()常量
{返回某物();}
模板
std::如果启用,则启用&
得到()
{返回somethingthesist();}
int&something()常量;
浮动&somethingthesis();
类嵌套
{
公众:
嵌套();
模板
constexpr std::启用&
get()常量{return foo.get();}
模板
std::如果启用,则启用&
get(){return foo.get();}
私人:
富和富;
};
};
类栏:公共Foo::嵌套 { void nonstfn() { [maybe_unused]]auto&a=get(); [maybe_unused]]auto&b=get(); } void constFn()常量 { [maybe_unused]]auto&a=get(); } };
首先,您需要
启用\u if::type
,SFINAE才能工作

要回答您的问题,您需要重载
Nested::get

#include <type_traits>

struct Foo
{
    template <typename T>
    constexpr std::enable_if_t<std::is_integral_v<T>, T>&
    get() const
    { return something(); }

    template <typename T>
    std::enable_if_t<std::is_floating_point_v<T>, T>&
    get()
    { return somethingDifferent(); }

    int& something() const;
    float& somethingDifferent();

    class Nested
    {
    public:
        Nested();

        template <typename T>
        constexpr std::enable_if_t<std::is_integral_v<T>, T>&
        get() const { return foo.get<T>(); }

        template <typename T>
        std::enable_if_t<std::is_floating_point_v<T>, T>&
        get() { return foo.get<T>(); }

    private:
        Foo& foo;
    };
};
#包括
结构Foo
{
模板
constexpr std::启用&
get()常量
{返回某物();}
模板
std::如果启用,则启用&
得到()
{返回somethingthesist();}
int&something()常量;
浮动&somethingthesis();
类嵌套
{
公众:
嵌套();
模板
constexpr std::启用&
get()常量{return foo.get();}
模板
std::如果启用,则启用&
get(){return foo.get();}
私人:
富和富;
};
};
类栏:公共Foo::嵌套 { void nonstfn() { [maybe_unused]]auto&a=get(); [maybe_unused]]auto&b=get(); } void constFn()常量 { [maybe_unused]]auto&a=get(); } };
在嵌套的
中需要常量和非常量重载,可以避免用另一个(简单的)SFINAE重复所有重载/SFINAE:

类嵌套
{
Foo&Foo;//应在decltype用法之前声明
公众:
嵌套();
模板
constexpr auto get()const->(decltype(foo.get()){return foo.get();}
模板
constexpr auto get()->(decltype(foo.get()){return foo.get();}
};

在嵌套的
中需要常量和非常量重载,可以避免用另一个(简单的)SFINAE重复所有重载/SFINAE:

类嵌套
{
Foo&Foo;//应在decltype用法之前声明
公众:
嵌套();
模板
constexpr auto get()const->(decltype(foo.get()){return foo.get();}
模板
constexpr auto get()->(decltype(foo.get()){return foo.get();}
};

考虑以下问题,这些问题毫无意义,但可以为您的问题提供解决方案。您有一个包含两个函数的类和它们的调用程序

class A
{
public: void foo() { printf("foo"); }
public: void foo() const { printf("foo const"); }
public: void invoke() { foo(); }
}
如果执行
A().invoke()
,显然会得到
foo
。如果您想强制执行
const
type函数,您是如何实现的?好的,您进行以下更改
A::invoke(){const_cast(this)->foo();}
就是这样。

考虑下面的问题,这个问题毫无意义,但可以为您的问题提供解决方案。您有一个包含两个函数的类和它们的调用程序

class A
{
public: void foo() { printf("foo"); }
public: void foo() const { printf("foo const"); }
public: void invoke() { foo(); }
}
如果执行
A().invoke()
,显然会得到
foo
。如果您想强制执行
const
type函数,您是如何实现的?好的,您进行以下更改
A::invoke(){const_cast(this)->foo();}
就是这样。

请始终添加语言标记您完成了大部分工作,只需将代码剥离到相关部分即可。您只需要创建一个实际的。我想回答您的问题,为此我需要测试我的解决方案,但我没有可以编译的代码。首先,我需要编译您的代码(Foo部分),这是您应该做的事情。如果不是在我们的时间,想想你没有得到的潜在答案,因为人们看到他们必须做你的工作来帮助你时,他们只是继续前进。请始终添加语言标记,通过将代码剥离到相关部分,你完成了大部分工作。您只需要创建一个实际的。我想回答您的问题,为此我需要测试我的解决方案,但我没有可以编译的代码。首先,我需要编译您的代码(Foo部分),这是您应该做的事情。如果不是因为我们的t
class Nested
{
    Foo& foo; // Should be declared before the decltype usage
public:
    Nested();

    template <typename T>
    constexpr auto get() const -> (decltype(foo.get<T>())) { return foo.get<T>(); }

    template <typename T>
    constexpr auto get() -> (decltype(foo.get<T>())) { return foo.get<T>(); }
};
class A
{
public: void foo() { printf("foo"); }
public: void foo() const { printf("foo const"); }
public: void invoke() { foo(); }
}