How to call a templated function if it exists, and

2019-03-08 04:00发布

I want to do something like

template <typename T>
void foo(const T& t) {
   IF bar(t) would compile
      bar(t);
   ELSE
      baz(t);
}

I thought that something using enable_if would do the job here, splitting up foo into two pieces, but I can't seem to work out the details. What's the simplest way of achieving this?

7条回答
可以哭但决不认输i
2楼-- · 2019-03-08 04:24

EDIT: I spoke too soon! litb's answer shows how this can actually be done (at the possible cost of your sanity... :-P)

Unfortunately I think the general case of checking "would this compile" is out of reach of function template argument deduction + SFINAE, which is the usual trick for this stuff. I think the best you can do is to create a "backup" function template:

template <typename T>
void bar(T t) {   // "Backup" bar() template
    baz(t);
}

And then change foo() to simply:

template <typename T>
void foo(const T& t) {
    bar(t);
}

This will work for most cases. Because the bar() template's parameter type is T, it will be deemed "less specialised" when compared with any other function or function template named bar() and will therefore cede priority to that pre-existing function or function template during overload resolution. Except that:

  • If the pre-existing bar() is itself a function template taking a template parameter of type T, an ambiguity will arise because neither template is more specialised than the other, and the compiler will complain.
  • Implicit conversions also won't work, and will lead to hard-to-diagnose problems: Suppose there is a pre-existing bar(long) but foo(123) is called. In this case, the compiler will quietly choose to instantiate the "backup" bar() template with T = int instead of performing the int->long promotion, even though the latter would have compiled and worked fine!

In short: there's no easy, complete solution, and I'm pretty sure there's not even a tricky-as-hell, complete solution. :(

查看更多
登录 后发表回答