混合模板、多重继承和非默认构造函数

问题描述 投票:0回答:1

我有一个实现某些功能的基类,以及一个实际上扩展它的模板类。基类有一个非默认构造函数,因为它需要一些配置数据。该模板有一个默认构造函数。

class Base
{
public:
    explicit Base(int data): m_data{data} {}
    int boilerplate(int x) const { return x + m_data; }
protected:
    int m_data;
};

template<typename T>
class Test: public virtual Base
{
public:
    virtual int foo(T x) const { return x + m_data; } // works by default for integers for convenience
};

我正在尝试创建一个继承自模板的多个专业化的类,它可以将相同的数据传递给单个虚拟基类。

class MultiTest : public Test<float>, public Test<double>
{
public:
    int foo(float x) const override { return x * static_cast<float>(boilerplate(3)); }
    int foo(double x) const override { return x / static_cast<double>(boilerplate(10)); }
};

如果我使用整数参数实例化该类,则会收到错误:

int main() { MultiTest x{32}; }
$ g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:24:26: error: no matching function for call to ‘MultiTest::MultiTest(<brace-enclosed initializer list>)’
   24 | int main() { MultiTest x{32}; }
      |                            ^
test.cpp:17:7: note: candidate: ‘MultiTest::MultiTest(const MultiTest&)’
   17 | class MultiTest : public Test<float>, public Test<double>
      |       ^~~~~~~~~
test.cpp:17:7: note:   no known conversion for argument 1 from ‘int’ to ‘const MultiTest&’
test.cpp:17:7: note: candidate: ‘MultiTest::MultiTest(MultiTest&&)’
test.cpp:17:7: note:   no known conversion for argument 1 from ‘int’ to ‘MultiTest&&’

我不能做

int main() { MultiTest x; } with no arguments either of course, since the 
Base`类没有默认构造函数:

$ g++ test.cpp 
test.cpp: In function ‘int main()’:
test.cpp:24:24: error: use of deleted function ‘MultiTest::MultiTest()’
   24 | int main() { MultiTest x; }
      |                        ^
test.cpp:17:7: note: ‘MultiTest::MultiTest()’ is implicitly deleted because the default definition would be ill-formed:
   17 | class MultiTest : public Test<float>, public Test<double>
      |       ^~~~~~~~~
test.cpp:17:7: error: use of deleted function ‘Test<float>::Test()’
test.cpp:11:7: note: ‘Test<float>::Test()’ is implicitly deleted because the default definition would be ill-formed:
   11 | class Test: public virtual Base
      |       ^~~~
test.cpp:11:7: error: no matching function for call to ‘Base::Base()’
test.cpp:4:14: note: candidate: ‘Base::Base(int)’
    4 |     explicit Base(int data): m_data{data} {}
      |              ^~~~
test.cpp:4:14: note:   candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr Base::Base(const Base&)’
    1 | class Base
      |       ^~~~
test.cpp:1:7: note:   candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr Base::Base(Base&&)’
test.cpp:1:7: note:   candidate expects 1 argument, 0 provided
test.cpp:17:7: error: use of deleted function ‘Test<double>::Test()’
   17 | class MultiTest : public Test<float>, public Test<double>
      |       ^~~~~~~~~
test.cpp:11:7: note: ‘Test<double>::Test()’ is implicitly deleted because the default definition would be ill-formed:
   11 | class Test: public virtual Base
      |       ^~~~
test.cpp:11:7: error: no matching function for call to ‘Base::Base()’
test.cpp:4:14: note: candidate: ‘Base::Base(int)’
    4 |     explicit Base(int data): m_data{data} {}
      |              ^~~~
test.cpp:4:14: note:   candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr Base::Base(const Base&)’
    1 | class Base
      |       ^~~~
test.cpp:1:7: note:   candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr Base::Base(Base&&)’
test.cpp:1:7: note:   candidate expects 1 argument, 0 provided
test.cpp:17:7: error: no matching function for call to ‘Base::Base()’
   17 | class MultiTest : public Test<float>, public Test<double>
      |       ^~~~~~~~~
test.cpp:4:14: note: candidate: ‘Base::Base(int)’
    4 |     explicit Base(int data): m_data{data} {}
      |              ^~~~
test.cpp:4:14: note:   candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr Base::Base(const Base&)’
    1 | class Base
      |       ^~~~
test.cpp:1:7: note:   candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr Base::Base(Base&&)’
test.cpp:1:7: note:   candidate expects 1 argument, 0 provided

如果我尝试在

Base
中添加对
MultiTest
构造函数的调用,例如与
explicit MultiTest(int data): Base{data} {}
发生类似的事情:

$ g++ test.cpp 
test.cpp: In constructor ‘MultiTest::MultiTest(int)’:
test.cpp:20:44: error: use of deleted function ‘Test<float>::Test()’
   20 |     explicit MultiTest(int data): Base{data} {}
      |                                            ^
test.cpp:11:7: note: ‘Test<float>::Test()’ is implicitly deleted because the default definition would be ill-formed:
   11 | class Test: public virtual Base
      |       ^~~~
test.cpp:11:7: error: no matching function for call to ‘Base::Base()’
test.cpp:4:14: note: candidate: ‘Base::Base(int)’
    4 |     explicit Base(int data): m_data{data} {}
      |              ^~~~
test.cpp:4:14: note:   candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr Base::Base(const Base&)’
    1 | class Base
      |       ^~~~
test.cpp:1:7: note:   candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr Base::Base(Base&&)’
test.cpp:1:7: note:   candidate expects 1 argument, 0 provided
test.cpp:20:44: error: use of deleted function ‘Test<double>::Test()’
   20 |     explicit MultiTest(int data): Base{data} {}
      |                                            ^
test.cpp:11:7: note: ‘Test<double>::Test()’ is implicitly deleted because the default definition would be ill-formed:
   11 | class Test: public virtual Base
      |       ^~~~
test.cpp:11:7: error: no matching function for call to ‘Base::Base()’
test.cpp:4:14: note: candidate: ‘Base::Base(int)’
    4 |     explicit Base(int data): m_data{data} {}
      |              ^~~~
test.cpp:4:14: note:   candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr Base::Base(const Base&)’
    1 | class Base
      |       ^~~~
test.cpp:1:7: note:   candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr Base::Base(Base&&)’
test.cpp:1:7: note:   candidate expects 1 argument, 0 provided

我也尝试过

explicit MultiTest(int data): Test<float>{data}, Test<double>{data} {}
:

$ g++ test.cpp 
test.cpp: In constructor ‘MultiTest::MultiTest(int)’:
test.cpp:20:71: error: no matching function for call to ‘Base::Base()’
   20 |     explicit MultiTest(int data): Test<float>{data}, Test<double>{data} {}
      |                                                                       ^
test.cpp:4:14: note: candidate: ‘Base::Base(int)’
    4 |     explicit Base(int data): m_data{data} {}
      |              ^~~~
test.cpp:4:14: note:   candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr Base::Base(const Base&)’
    1 | class Base
      |       ^~~~
test.cpp:1:7: note:   candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr Base::Base(Base&&)’
test.cpp:1:7: note:   candidate expects 1 argument, 0 provided
test.cpp:20:71: error: no matching function for call to ‘Test<float>::Test(<brace-enclosed initializer list>)’
   20 |     explicit MultiTest(int data): Test<float>{data}, Test<double>{data} {}
      |                                                                       ^
test.cpp:11:7: note: candidate: ‘Test<float>::Test(const Test<float>&)’
   11 | class Test: public virtual Base
      |       ^~~~
test.cpp:11:7: note:   no known conversion for argument 1 from ‘int’ to ‘const Test<float>&’
test.cpp:11:7: note: candidate: ‘Test<float>::Test(Test<float>&&)’
test.cpp:11:7: note:   no known conversion for argument 1 from ‘int’ to ‘Test<float>&&’
test.cpp:20:71: error: no matching function for call to ‘Test<double>::Test(<brace-enclosed initializer list>)’
   20 |     explicit MultiTest(int data): Test<float>{data}, Test<double>{data} {}
      |                                                                       ^
test.cpp:11:7: note: candidate: ‘Test<double>::Test(const Test<double>&)’
   11 | class Test: public virtual Base
      |       ^~~~
test.cpp:11:7: note:   no known conversion for argument 1 from ‘int’ to ‘const Test<double>&’
test.cpp:11:7: note: candidate: ‘Test<double>::Test(Test<double>&&)’
test.cpp:11:7: note:   no known conversion for argument 1 from ‘int’ to ‘Test<double>&&’

并获得了类似的结果

explicit MultiTest(int data): Test<float>{data}, Test<double>{data}, Base{data} {}
:

$ g++ test.cpp 
test.cpp: In constructor ‘MultiTest::MultiTest(int)’:
test.cpp:20:83: error: no matching function for call to ‘Test<float>::Test(<brace-enclosed initializer list>)’
   20 |     explicit MultiTest(int data): Test<float>{data}, Test<double>{data}, Base{data} {}
      |                                                                                   ^
test.cpp:11:7: note: candidate: ‘Test<float>::Test(const Test<float>&)’
   11 | class Test: public virtual Base
      |       ^~~~
test.cpp:11:7: note:   no known conversion for argument 1 from ‘int’ to ‘const Test<float>&’
test.cpp:11:7: note: candidate: ‘Test<float>::Test(Test<float>&&)’
test.cpp:11:7: note:   no known conversion for argument 1 from ‘int’ to ‘Test<float>&&’
test.cpp:20:83: error: no matching function for call to ‘Test<double>::Test(<brace-enclosed initializer list>)’
   20 |     explicit MultiTest(int data): Test<float>{data}, Test<double>{data}, Base{data} {}
      |                                                                                   ^
test.cpp:11:7: note: candidate: ‘Test<double>::Test(const Test<double>&)’
   11 | class Test: public virtual Base
      |       ^~~~
test.cpp:11:7: note:   no known conversion for argument 1 from ‘int’ to ‘const Test<double>&’
test.cpp:11:7: note: candidate: ‘Test<double>::Test(Test<double>&&)’
test.cpp:11:7: note:   no known conversion for argument 1 from ‘int’ to ‘Test<double>&&’

我需要对

MultiTest
main
做什么才能使这项工作成功?还有,为什么?

c++ templates virtual-inheritance diamond-problem
1个回答
0
投票

您需要提供一些额外的构造函数:

template<typename T>
class Test: public virtual Base
{
public:
    explicit Test (int data) : Base (data) { } // <==

    virtual int foo(T x) const { return x + m_data; } // works by default for integers for convenience
};

和:

class MultiTest : public Test<float>, public Test<double>
{
public:
    explicit MultiTest (int data) : Base (data), Test <float> (data), Test <double> (data) { } // <==

    int foo(float x) const override { return x * static_cast<float>(boilerplate(3)); }
    int foo(double x) const override { return x / static_cast<double>(boilerplate(10)); }
};

顺便说一句,我不能说我很喜欢整个想法。

© www.soinside.com 2019 - 2024. All rights reserved.