草庐IT

c++ - 当重载具有多重继承的函数时,GCC 说调用它是不明确的,但 Clang 和 MSVC 没有

coder 2023-11-17 原文

我正在使用这个变体库:https://github.com/cbeck88/strict-variant .它提供了一个类似于std::variantboost::variant 的类。鉴于此 struct:

struct S
{
    explicit S(double) {}
};

我想这样做:

strict_variant::variant<double, S> v = 2.0;

这适用于 Clang 5.0.1 和 MSVC 19.12.25831.00,但无法使用 GCC 7.2.1 进行编译。

我查看了库的代码并将问题简化为:

#include <iostream>

struct S
{
    constexpr S() {}
    constexpr explicit S(double) {}
};

template<unsigned i> struct init_helper;
template<> struct init_helper<0> { using type = double; };
template<> struct init_helper<1> { using type = S; };

template<unsigned i>
struct initializer_leaf
{
    using target_type = typename init_helper<i>::type;
    constexpr unsigned operator()(target_type) const
    {
        return i;
    }
};

struct initializer : initializer_leaf<0>, initializer_leaf<1>
{
};

int main()
{
    std::cout << initializer()(double{}) << " = double" << '\n';
    std::cout << initializer()(S{}) << " = S" << '\n';

    return 0;
}

输出为

0 = double
1 = S

海湾合作委员会说:

strict_variant_test.cpp: In function ‘int main()’:
strict_variant_test.cpp:29:37: error: request for member ‘operator()’ is ambiguous
  std::cout << initializer()(double{}) << " = double" << '\n';
                                     ^
strict_variant_test.cpp:17:21: note: candidates are: constexpr unsigned int initializer_leaf<i>::operator()(initializer_leaf<i>::target_type) const [with unsigned int i = 1; initializer_leaf<i>::target_type = S]
  constexpr unsigned operator()(target_type) const
                     ^~~~~~~~
strict_variant_test.cpp:17:21: note:                 constexpr unsigned int initializer_leaf<i>::operator()(initializer_leaf<i>::target_type) const [with unsigned int i = 0; initializer_leaf<i>::target_type = double]
strict_variant_test.cpp:30:32: error: request for member ‘operator()’ is ambiguous
  std::cout << initializer()(S{}) << " = S" << '\n';
                                ^
strict_variant_test.cpp:17:21: note: candidates are: constexpr unsigned int initializer_leaf<i>::operator()(initializer_leaf<i>::target_type) const [with unsigned int i = 1; initializer_leaf<i>::target_type = S]
  constexpr unsigned operator()(target_type) const
                     ^~~~~~~~
strict_variant_test.cpp:17:21: note:                 constexpr unsigned int initializer_leaf<i>::operator()(initializer_leaf<i>::target_type) const [with unsigned int i = 0; initializer_leaf<i>::target_type = double]

但是,当我将 initializer 的定义更改为:

struct initializer
{
    constexpr unsigned operator()(double) const
    {
        return 0;
    }

    constexpr unsigned operator()(S) const
    {
        return 1;
    }
};

我对 C++ 的理解表明这是等价的,所以我认为这是 GCC 中的错误,但我经常遇到标准说出令人惊讶的事情而我的假设是错误的问题。所以,我的问题是:这是谁的错? GCC 是否有错误,Clang 和 MSVC 是否有错误,或者代码的解释是否未定义/未指定以便所有编译器都是正确的?如果代码错误,如何修复?

最佳答案

这实际上是一个 clang 错误。

根据经验,不同 范围内的名称不会重载。这是一个简化的例子:

template <typename T>
class Base {
public:
    void foo(T ) { }
};

template <typename... Ts>
struct Derived: Base<Ts>...
{};

int main()
{
    Derived<int, double>().foo(0); // error
}

这应该是一个错误,因为 class member lookup rules声明基本上只有一个基类可以包含给定名称。如果多个基类具有相同的名称,则查找是不明确的。此处的解决方案是使用 using 声明将两个 基类名称引入派生类。在 C++17 中,using 声明可以是一个包扩展,这使得这个问题变得容易得多:

template <typename T>
class Base {
public:
    void foo(T ) { }
};

template <typename... Ts>
struct Derived: Base<Ts>...
{
    using Base<Ts>::foo...;
};

int main()
{
    Derived<int, double>().foo(0); // ok! calls Base<int>::foo
}

对于特定的库,this code :

template <typename T, unsigned... us>
  struct initializer_base<T, mpl::ulist<us...>> : initializer_leaf<T, us>... {
      static_assert(sizeof...(us) > 0, "All value types were inelligible!");
  };

应该看起来像:

template <typename T, unsigned... us>
struct initializer_base<T, mpl::ulist<us...>> : initializer_leaf<T, us>... {
    static_assert(sizeof...(us) > 0, "All value types were inelligible!");
    using initializer_leaf<T, us>::operator()...; // (*) <==
};

(虽然我猜该库的目标是 C++11,所以我提交了一个符合 C++11 的修复程序……只是有点冗长)。

关于c++ - 当重载具有多重继承的函数时,GCC 说调用它是不明确的,但 Clang 和 MSVC 没有,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47935500/

有关c++ - 当重载具有多重继承的函数时,GCC 说调用它是不明确的,但 Clang 和 MSVC 没有的更多相关文章

  1. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby-on-rails - 无法在centos上安装therubyracer(V8和GCC出错) - 2

    我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e

  4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  5. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  6. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  7. ruby-on-rails - Rails 3.1 中具有相同形式的多个模型? - 2

    我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#

  8. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  9. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  10. ruby-on-rails - Rails 单表继承 : How to override the value written to the type field - 2

    在我的系统中,我已经定义了STI。Dog继承自Animal,在animals表中有一个type列,其值为"Dog"。现在我想让SpecialDog继承自dog,只是为了在某些特殊情况下稍微修改一下行为。数据还是一样。我需要通过SpecialDog运行的所有查询,以返回数据库中类型为Dog的值。我的问题是因为我有一个type列,rails将WHERE"animals"."type"IN('SpecialDog')附加到我的查询中,所以我不能获取原始的Dog条目。所以我想要的是以某种方式覆盖rails在通过SpecialDog访问数据库时使用的值,使其表现得像Dog。有没有办法覆盖用于类型

随机推荐