Right, the identity function is just a dummy adapter for the simple degenerate case.
Generate a report, given any one of the following data sources:
AccountingDataSource companyExpenseList; /* { currency amount, std::string expenseIncurredBy; std::string paidTo; } */
SantasNaughtyOrNiceList santasList; /* { std::string kidName; bool naughty; } I was good! I swear! */
HitList hitList; /* { std::string name; } A name is all you need to know */ 
Without adapters:
void GenerateReport(DataSource& dataSource) {
  ...
  for (auto& row : dataSource) {
    std::string userName = "";
    if (accountingRow = dynamic_cast<AccountingRow&>(row)) {
      userName = accountingRow.expenseIncurredBy;
    } else if (naughtyInfo = dynamic_cast<NaughtInfo&>(row)) {
      userName = naughtyInfo.kidName;
    } else if (name = dynamic_cast<String&>(row)) {
      userName = name;
    }
    ...
  }
  ...
}
GenerateReport(oneOfTheDataSources);
With adapters, but lacking identity:
void BuildReport(DataSource& dataSource, UsernameFn* getUserName) {
  ...
  for (auto& row : dataSource) {
    auto userName = getUserName(row);
    std::string userName = "";
    if (getUserName != null) {
      userName = getUserName(row)
    } else {
      userName = row; /* Data consists of just a name */
    }
    ...
  }
  ...
}
std::string accountingExpenseUserName(AccountingRow& row) { return row.expenseIncurredBy; }
std::string accountingPaidToUserName(AccountingRow& row) { return row.paidTo; }
GenerateReport(companyExpenseList, accountingExpenseUserName);
GenerateReport(companyExpenseList, accountingPaidToUserName);  /* Can choose alternate fields, not based solely on type */
GenerateReport(hitList, null); /* Not much adapting to do here. You have what you need. */
With adapters, and identity function:
void BuildReport(DataSource& dataSource, UsernameFn* getUserName) {
  ...
  for (auto& row : dataSource) {
    auto userName = getUserName(row);
    ...
  }
  ...
}
std::string accountingExpenseUserName(AccountingRow& row) { return row.expenseIncurredBy; }
std::string accountingPaidToUserName(AccountingRow& row) { return row.paidTo; }
std::string identityFunction(std::string name) { return name; }
GenerateReport(companyExpenseList, accountingExpenseUserName);
GenerateReport(companyExpenseList, accountingPaidToUserName);  /* Can choose alternate fields, not based solely on type */
GenerateReport(hitList, identityFunction); /* Not much adapting to do here. You have what you need. */
You'll notice the hitman isn't too picky about the identity function. 
