2

たとえば、次のコードがあるとします。

class A {
 public:
    double operator()(double foo) {
        return foo;
    }
};

class B {
 public:
    double operator()(double foo, int bar) {
        return foo + bar;
    }
};

の 2 つのバージョンを書きたいと思います。1funつは A の署名を持つオブジェクトで動作し、もう 1 つは B の署名を持つオブジェクトで動作します。

template <typename F, typename T>
T fun(F f, T t) {
    return f(t);
}

template <typename F, typename T>
T fun(F f, T t) {
    return f(t, 2);
}

そして、私はこの動作を期待しています

A a();
B b();
fun(a, 4.0);  // I want this to be 4.0
fun(b, 4.0);  // I want this to be 6.0

もちろん、前の例では、コンパイル時にテンプレートの再定義エラーがスローされます。

B が代わりに関数である場合、次のfunように書き直すことができます。

template <typename T>
T fun(T (f)(T, int), T t) {
    return f(t, 2);
}

funしかし、関数と呼び出し可能なオブジェクトの両方で作業したいと考えています。std::bindまたはを使用std::functionすると問題が解決する可能性がありますが、私は C++98 を使用しており、それらは C++11 で導入されました。

4

1 に答える 1

1

void を返す関数に対応するために、この質問から変更されたソリューションを次に示します。解決策は、単に使用することsizeof(possibly-void-expression, 1)です。

#include <cstdlib>
#include <iostream>

// like std::declval in c++11
template <typename T>
T& decl_val();

// just use the type and ignore the value. 
template <std::size_t, typename T = void> 
struct ignore_value {typedef T type;};

// This is basic expression-based SFINAE.
// If the expression inside sizeof() is invalid, substitution fails.
// The expression, when valid, is always of type int, 
// thanks to the comma operator.
// The expression is valid if an F is callable with specified parameters. 
template <class F>
typename ignore_value<sizeof(decl_val<F>()(1),1), void>::type
call(F f)
{
    f(1);
}

// Same, with different parameters passed to an F.
template <class F>
typename ignore_value<sizeof(decl_val<F>()(1,1),1), void>::type
call(F f)
{
    f(1, 2);
}

void func1(int) { std::cout << "func1\n"; }
void func2(int,int) { std::cout << "func2\n"; }

struct A
{
    void operator()(int){ std::cout << "A\n"; }
};

struct B
{
    void operator()(int, int){ std::cout << "B\n"; }
};

struct C
{
    void operator()(int){ std::cout << "C1\n"; }
    void operator()(int, int){ std::cout << "C2\n"; }
};

int main()
{
    call(func1);
    call(func2);
    call(A());
    call(B());
    // call(C()); // ambiguous
}

c++98 モードの gcc と clang で確認済み。

于 2018-04-10T03:06:44.293 に答える