2017-08-28 92 views
3

这里是我的代码:变:没有匹配函数调用“得到”

#include <iostream> 
#include <variant> 
#include <vector> 

class A { 
public: 
    virtual void Foo() = 0;  
}; 

class B : public A { 
public: 
    void Foo() override { 
     std::cout << "B::Foo()" << std::endl; 
    } 
}; 

class C :public A { 
public: 
    void Foo() override { 
     std::cout << "C::Foo()" << std::endl; 
    } 
}; 

template<typename... Args> 
class D { 
public: 
    template<typename T> 
    void Foo() { 
     m_variant = T{}; 
    } 

    void Bar() { 
     std::get<m_variant.index()>(m_variant).Foo(); 
    } 

private: 
    std::variant<std::monostate, Args...> m_variant; 
}; 

int main() { 
    D<B, C> d; 
    d.Foo<B>(); 
    d.Bar(); 

    d.Foo<C>(); 
    d.Bar(); 
} 

(c.f wandbox.org

,我发现了错误no matching function for call to 'get'但我不明白为什么。 std::variant::index()是constexpr,所以它不是问题(我通过直接测试值1,但仍然是相同的错误)。
我有一个std::monostate防止空变种(当无参数是typename... Args

+5

'm_variant.index()'是一个运行时的值,使用访问者,而不是('的std ::访问([] (auto&e){e.Foo();},m_variant);')。 – Jarod42

+3

尽管''index'](http://en.cppreference.com/w/cpp/utility/variant/index)函数被标记为“constexpr”,变量'm_variant'是* not *并且可以因此不能在编译时使用。 –

+3

只有当变量对象被调用是一个常量表达式时,'std :: variant :: index()'的结果才是一个常量表达式。你的不是。 – StoryTeller

回答

4

m_variant.index()是一个运行时值(因为m_variant不是常量表达式)。

派遣的方式是使用访问者,如:

std::visit([](auto& v) { v.Foo(); }, m_variant); 

Demo

+0

请您简单解释“过载”是如何工作的?我见过[std :: visit](http://en.cppreference.com/w/cpp/utility/variant/visit)文档,但没有在那里解释。 – AMA

+1

它允许用'operator()'分组几个函子。这允许在lambda表达式的调用位置构建,而不是为'operator()'的所有重载编写一个专用函子。 – Jarod42

+1

@AMA - 请参阅[这里](https://stackoverflow.com/questions/45020573/using-stdvisit-with-variadic-template-struct/45020724#45020724)的解释。 – StoryTeller

1

东西打上constexpr告诉你,在某些情况下,它可以在编译时被调用。它确实而不是保证它始终可以在编译时调用。

我的variant的情况下,index可以在编译时被称为如果变体本身就是一个constexpr值。否则,它是一种运行时方法。

您可以阅读关于什么时候可以在编译时调用的文档或关于它的原因的文档;在这种情况下,如果变体的类型可能在运行时发生变化,index如何成为编译时间常量?请记住,只有值的ttpe和constexpr- ness,加上如果它本身在编译时的上下文中,可以用来推理“这可以在编译时调用”。

相关问题